<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:fh="http://purl.org/syndication/history/1.0"><channel><title>Cratis Blog</title><description>Essays and engineering notes on event sourcing, CQRS, and building with Chronicle, Arc, and the rest of the Cratis stack.</description><link>https://blog.cratis.io/</link><language>en</language><atom:link rel="self" href="https://blog.cratis.io/rss.xml"/><atom:link rel="prev-archive" href="https://blog.cratis.io/rss/2026-10.xml"/><item><title>Questions and a decision guide · Decisions that hold, Part 11</title><link>https://blog.cratis.io/decisions-that-hold-faq/</link><guid isPermaLink="true">https://blog.cratis.io/decisions-that-hold-faq/</guid><description>Ten posts on keeping a decision true at the moment it is written, and one page that tells you which mechanism a rule needs, what fails without an error, and where each answer is explained in full.</description><pubDate>Tue, 17 Nov 2026 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://blog.cratis.io/the-bug-you-never-see/&quot;&gt;Decisions that hold&lt;/a&gt; · Part 11 of 11&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This series started from a bug most applications have and few tests find: a rule reads state, decides, and writes, and two requests can both pass the check before either writes. Parts 2 to 6 made one tool dependable for that, Arc’s read protection, which turns a read model in a command into a guard on the command’s append. Parts 7 to 10 covered the rules that need something else, the same guard without Arc, how to test it, and how a guard is built. This last part is the page to come back to: a decision guide by the shape of the rule, short answers to the questions the series raised, and where each one is explained.&lt;/p&gt;
&lt;p&gt;The answers assume read protection is On, as in new Cratis applications (&lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;Part 2&lt;/a&gt;), unless they say otherwise. Read protection, command scenarios and the Arc analyzers are part of Arc for .NET.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-decision-guide&quot;&gt;The decision guide&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Start from the rule, not from the tool. Ask these questions in order, and the first yes picks the mechanism:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/decision-guide.fvYPuDOE_240kRJ.webp&quot; alt=&quot;Seven numbered questions on the left, each with an arrow to a mechanism and the part that covers it. One: a value or event once? Constraint, Part 7. Two: no stored state needed? Stateless validator, Part 7. Three: fine to repair later? Reactor repair, Part 7. Four: client sent a revision? Explicit scope, Part 7. Five: one entity, many rules? Aggregate root, Part 7. Six: one routed stream? Stream model or decision, Part 4. Seven: otherwise, a guarded read under On, Parts 2 and 3.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2400&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Ask in order. A guarded read is what is left when none of the other shapes fits.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The table has more rows than the questions, because some rules have a shape the questions don’t separate. “Never rely on” is a choice that can fail silently: the command succeeds and the rule is broken. “Too much” is a choice that works and costs more than the rule needs.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rule shape&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;th&gt;Never rely on&lt;/th&gt;
&lt;th&gt;Too much&lt;/th&gt;
&lt;th&gt;Part&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A unique value (email, user name)&lt;/td&gt;
&lt;td&gt;A constraint: &lt;code dir=&quot;auto&quot;&gt;[Unique]&lt;/code&gt; on the event property&lt;/td&gt;
&lt;td&gt;A validator that asks “does it exist?”&lt;/td&gt;
&lt;td&gt;Read protection only for uniqueness&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://blog.cratis.io/not-every-rule-needs-a-guarded-read/&quot;&gt;7&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Created once (one library card per member)&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;[Unique]&lt;/code&gt; on the event type&lt;/td&gt;
&lt;td&gt;An “exists” check in a validator&lt;/td&gt;
&lt;td&gt;A read over the whole history&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://blog.cratis.io/not-every-rule-needs-a-guarded-read/&quot;&gt;7&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State on one key (stock, a count, a status)&lt;/td&gt;
&lt;td&gt;A read-model parameter under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, the rule in a &lt;code dir=&quot;auto&quot;&gt;CommandValidator&amp;#x3C;T&gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The same validator under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A constraint: it can’t count&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;2&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A rule over two keys (loans and stock)&lt;/td&gt;
&lt;td&gt;Two read-model parameters with &lt;code dir=&quot;auto&quot;&gt;[LookUpBy]&lt;/code&gt;, one event per key in one append&lt;/td&gt;
&lt;td&gt;Two aggregates, each guarding only its own source&lt;/td&gt;
&lt;td&gt;One model that folds both keys: it is refused&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://blog.cratis.io/one-rule-two-entities/&quot;&gt;3&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One stream of an entity (a month, a period)&lt;/td&gt;
&lt;td&gt;A per-stream read model, or a stream decision for “has it happened?”&lt;/td&gt;
&lt;td&gt;An injected read of the stream under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A whole-source read when one period matters&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://blog.cratis.io/a-limit-for-one-month/&quot;&gt;4&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;An editing conflict&lt;/td&gt;
&lt;td&gt;An explicit scope with the revision the client saw&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;concurrency: true&lt;/code&gt; alone&lt;/td&gt;
&lt;td&gt;A read model that folds what a revision tells you&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://blog.cratis.io/not-every-rule-needs-a-guarded-read/&quot;&gt;7&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rich behaviour on one entity&lt;/td&gt;
&lt;td&gt;An aggregate root that returns &lt;code dir=&quot;auto&quot;&gt;Commit()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ignoring the result of &lt;code dir=&quot;auto&quot;&gt;Commit()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A read model for each invariant&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://blog.cratis.io/not-every-rule-needs-a-guarded-read/&quot;&gt;7&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A rare, repairable violation&lt;/td&gt;
&lt;td&gt;The default append and a reactor that repairs&lt;/td&gt;
&lt;td&gt;The repair running before the harm&lt;/td&gt;
&lt;td&gt;Any guard&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://blog.cratis.io/not-every-rule-needs-a-guarded-read/&quot;&gt;7&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A hint on screen (“no copies left”)&lt;/td&gt;
&lt;td&gt;A query, or &lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt; on the read&lt;/td&gt;
&lt;td&gt;The hint as the rule&lt;/td&gt;
&lt;td&gt;A guarded read&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://blog.cratis.io/when-arc-says-no/&quot;&gt;5&lt;/a&gt;, &lt;a href=&quot;https://blog.cratis.io/not-every-rule-needs-a-guarded-read/&quot;&gt;7&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;External data (a price, a tax rate)&lt;/td&gt;
&lt;td&gt;Fetch it in &lt;code dir=&quot;auto&quot;&gt;Provide()&lt;/code&gt;; the guard covers your own state&lt;/td&gt;
&lt;td&gt;Assuming the external value is guarded&lt;/td&gt;
&lt;td&gt;Guarding state you don’t decide from&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://blog.cratis.io/not-every-rule-needs-a-guarded-read/#external-data&quot;&gt;7&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A hot key with a long history&lt;/td&gt;
&lt;td&gt;A key per period, order or booking, or a constraint&lt;/td&gt;
&lt;td&gt;A guarded read on a key that never stops growing&lt;/td&gt;
&lt;td&gt;A flat model over years of events&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;2&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code without Arc (an endpoint, a worker)&lt;/td&gt;
&lt;td&gt;A decision read passed to the append, or enrolled in the request’s unit of work&lt;/td&gt;
&lt;td&gt;A plain &lt;code dir=&quot;auto&quot;&gt;Append&lt;/code&gt; beside it, or an unchecked result&lt;/td&gt;
&lt;td&gt;Read protection on a unit of work for one guarded append&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://blog.cratis.io/decision-reads-without-arc/&quot;&gt;8&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/&quot;&gt;Choosing how a command’s rule holds&lt;/a&gt; has the same matrix, the flowchart and what each mechanism guards. Chronicle’s &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/choosing/&quot;&gt;Choosing how a rule holds&lt;/a&gt; makes the same choice from the client’s side, without Arc.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;questions-about-read-protection&quot;&gt;Questions about read protection&lt;/h2&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;does-a-validator-that-reads-a-read-model-make-my-rule-hold&quot;&gt;Does a validator that reads a read model make my rule hold?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;, the default, no. The validator gets a snapshot, a materialized model can lag behind the log as well, and nothing ties the commit to what the validator saw. Under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, yes, within the guard: the read is folded fresh from the event log, and the commit is refused if an event of the model’s types arrives for that key after the position Chronicle noted before the fold. It can’t make a value unique across keys, and it doesn’t see what’s listed under &lt;a href=&quot;#what-does-a-guard-not-cover&quot;&gt;what a guard doesn’t cover&lt;/a&gt;. See &lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;Part 2&lt;/a&gt; and Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/getting-started/&quot;&gt;Getting started&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;how-do-i-turn-it-on-and-why-isnt-it-on-by-default&quot;&gt;How do I turn it on, and why isn’t it on by default?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;One property in the project that contains the commands, or in a &lt;code dir=&quot;auto&quot;&gt;Directory.Build.props&lt;/code&gt; that covers several:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PropertyGroup&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;CratisReadProtection&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;On&lt;/span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;CratisReadProtection&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;PropertyGroup&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;It’s compiled into the assembly, and any value other than &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; fails the build. &lt;code dir=&quot;auto&quot;&gt;[ReadProtection(ReadProtectionMode.On)]&lt;/code&gt; turns on one command. New applications from the Cratis templates have &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; already. Arc’s own default is &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;, because a protected command fails closed: commands that read through &lt;code dir=&quot;auto&quot;&gt;IReadModels&lt;/code&gt; or append as a side effect would start failing. The next major version of Arc makes &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; the default (&lt;a href=&quot;https://github.com/Cratis/Arc/issues/3255&quot;&gt;Cratis/Arc#3255&lt;/a&gt;). You can then turn it off for one command with &lt;code dir=&quot;auto&quot;&gt;[ReadProtection(ReadProtectionMode.Off)]&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt;, for one read with &lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt;, and for a project with &lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;CratisReadProtection&gt;Off&amp;#x3C;/CratisReadProtection&gt;&lt;/code&gt;. See &lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;Part 2&lt;/a&gt; and &lt;a href=&quot;https://blog.cratis.io/turning-read-protection-on/&quot;&gt;Part 6&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;do-i-still-need-protecteddecision-and-decisionreadt&quot;&gt;Do I still need &lt;code dir=&quot;auto&quot;&gt;[ProtectedDecision]&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;DecisionRead&amp;#x3C;T&gt;&lt;/code&gt;?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; you don’t need &lt;code dir=&quot;auto&quot;&gt;[ProtectedDecision]&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;DecisionRead&amp;#x3C;T&gt;&lt;/code&gt;; they keep working. A plain read-model parameter is guarded, and so are a validator’s constructor parameters. Outside &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;[ProtectedDecision]&lt;/code&gt; is how one command opts in on its own, and Arc runs such a command’s validator only if it has no constructor parameters. See &lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;Part 2&lt;/a&gt; and Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/faq/&quot;&gt;FAQ&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;does-a-guard-lock-anything-and-what-does-it-cost&quot;&gt;Does a guard lock anything, and what does it cost?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Nothing is locked and nothing waits. Two commands on the same key both run to the commit, and the commit is where one of them may be refused. The cost is in the read: a fresh fold of the key’s history of the model’s event types on every guarded read, two tail reads per attempt, and up to three attempts if events arrive while it folds. Nothing caches the result between commands, and the kernel serves the folds through one projection per model type, shared by every key and tenant, so heavy use of one model type queues across keys. No benchmark of Arc’s read protection is published; Chronicle’s &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/limits/#what-a-decision-read-costs&quot;&gt;costs and limits&lt;/a&gt; page has one decision-read measurement with its environment. Keep guarded models flat and keys short-lived. See &lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;Part 2&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;what-does-a-guard-not-cover&quot;&gt;What does a guard not cover?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;A guard covers one key’s history, for the event types the model folds, after the position noted before the read. Outside it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;Revise&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;Redact&lt;/code&gt; between the read and the commit. They don’t move the tail, so they aren’t detected, and Chronicle refuses them inside a protected invocation.&lt;/li&gt;
&lt;li&gt;Other event sequences, services, HTTP calls and other databases.&lt;/li&gt;
&lt;li&gt;A projection definition changed by another process.&lt;/li&gt;
&lt;li&gt;Reads marked &lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt;, and every read under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;New keys a rule counts over. Put such a count on one key that receives every fact.&lt;/li&gt;
&lt;li&gt;A writer that decides without a guard. Your guard detects its event if it lands in your window, but its own decision is unguarded.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See &lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;Part 2&lt;/a&gt;, &lt;a href=&quot;https://blog.cratis.io/one-rule-two-entities/&quot;&gt;Part 3&lt;/a&gt; and Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/how-it-works/#what-is-outside-the-guard&quot;&gt;How it works&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;can-a-caller-skip-my-validator&quot;&gt;Can a caller skip my validator?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;, yes. A model-bound command honours the caller’s &lt;code dir=&quot;auto&quot;&gt;X-Allowed-Severity&lt;/code&gt;, and a caller that sends &lt;code dir=&quot;auto&quot;&gt;3&lt;/code&gt; (&lt;code dir=&quot;auto&quot;&gt;Error&lt;/code&gt;) removes the &lt;code dir=&quot;auto&quot;&gt;Error&lt;/code&gt; results of your validators and &lt;code dir=&quot;auto&quot;&gt;Provide()&lt;/code&gt;, unless the command declares &lt;code dir=&quot;auto&quot;&gt;[BlockOnValidationSeverity]&lt;/code&gt;. From Arc 22.108.0, a command declared &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, in the project or on the command, has an &lt;code dir=&quot;auto&quot;&gt;Error&lt;/code&gt; floor: &lt;code dir=&quot;auto&quot;&gt;Error&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;Unknown&lt;/code&gt; results block whatever the caller sends, and the caller can still let warnings through. The floor follows the declared mode, so a runtime cap doesn’t remove it, and a command’s own &lt;code dir=&quot;auto&quot;&gt;[BlockOnValidationSeverity]&lt;/code&gt; takes precedence. No threshold turns a &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt; from the commit into a success. See &lt;a href=&quot;https://blog.cratis.io/when-arc-says-no/&quot;&gt;Part 5&lt;/a&gt; and Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/commands/validation-severity-filtering/&quot;&gt;severity filtering&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;is-measure-a-safe-place-to-stay&quot;&gt;Is Measure a safe place to stay?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;No. &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; returns what &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; returns, with the same status codes, and reports what &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; would guard, refuse or reject through the counter &lt;code dir=&quot;auto&quot;&gt;cratis.arc.read_protection.events&lt;/code&gt; on the meter &lt;code dir=&quot;auto&quot;&gt;Cratis.Arc.ReadProtection&lt;/code&gt;, a span event and log warnings. An application in &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; is exactly as unguarded as one in &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;. The measurement is best effort and the race scan is sampled, so a quiet report is not evidence that nothing would change. Use it to find what to fix, then switch a project to &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;. To back out after a deployment, &lt;code dir=&quot;auto&quot;&gt;ReadProtection:MaximumMode&lt;/code&gt; lowers the mode at run time and never raises it. See &lt;a href=&quot;https://blog.cratis.io/turning-read-protection-on/&quot;&gt;Part 6&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;questions-about-refusals&quot;&gt;Questions about refusals&lt;/h2&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;does-arc-retry-a-command-that-conflicted&quot;&gt;Does Arc retry a command that conflicted?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;No. Arc and Chronicle do not re-run the command. A lost race returns a &lt;code dir=&quot;auto&quot;&gt;400&lt;/code&gt; with the reason &lt;code dir=&quot;auto&quot;&gt;concurrencyViolation&lt;/code&gt;, the detail &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt; and a state of &lt;code dir=&quot;auto&quot;&gt;{ readModel, key }&lt;/code&gt;, and nothing from the command is written. The fold makes up to three attempts while it reads, before your code decides; after that, a conflict ends the command. The caller reads again and decides again. Resubmitting the same decision in a loop would undo the point of the guard. The message doesn’t name the event that conflicted. See &lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;Part 2&lt;/a&gt; and &lt;a href=&quot;https://blog.cratis.io/when-arc-says-no/&quot;&gt;Part 5&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;what-should-a-ui-do-with-readchanged-and-readincomplete&quot;&gt;What should a UI do with &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;ReadIncomplete&lt;/code&gt;?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Both are &lt;code dir=&quot;auto&quot;&gt;400&lt;/code&gt;s with the reason &lt;code dir=&quot;auto&quot;&gt;concurrencyViolation&lt;/code&gt;, and both mean nothing was written. &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt; means something the command read changed before the commit: reload what the user decided from and let them decide again. &lt;code dir=&quot;auto&quot;&gt;ReadIncomplete&lt;/code&gt; means the fold didn’t reach that key’s latest events in three attempts: submitting again is safe. Branch on &lt;code dir=&quot;auto&quot;&gt;reason&lt;/code&gt;; &lt;code dir=&quot;auto&quot;&gt;reasonDetail&lt;/code&gt; is a plain string with no TypeScript constant, the message is developer text, and neither result names a field. See &lt;a href=&quot;https://blog.cratis.io/when-arc-says-no/&quot;&gt;Part 5&lt;/a&gt; and Arc’s &lt;a href=&quot;https://www.cratis.io/arc/frontend/core/commands/command-result/&quot;&gt;command result&lt;/a&gt; page.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;why-does-my-command-return-a-500-under-on&quot;&gt;Why does my command return a &lt;code dir=&quot;auto&quot;&gt;500&lt;/code&gt; under On?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Usually the command reads or appends something Arc can’t put under a guard. The common causes are a read model with joins, children or a key taken from an event property, a filtered reducer or one with dependencies, a read through &lt;code dir=&quot;auto&quot;&gt;IReadModels&lt;/code&gt; or the event log inside the command, an immediate &lt;code dir=&quot;auto&quot;&gt;IEventLog.Append&lt;/code&gt;, an aggregate and a read of the same source, or a validator registered by hand as scoped, as a singleton, or through a factory or an instance (a plain transient registration is fine). &lt;a href=&quot;https://blog.cratis.io/when-arc-says-no/&quot;&gt;Part 5&lt;/a&gt; lists the rest. Nothing is written, and submitting again fails the same way, so the code has to change. Outside Development, the message is replaced by a generic one unless &lt;code dir=&quot;auto&quot;&gt;ArcOptions.ExposeExceptionDetails&lt;/code&gt; is set; find the full text in the server log by the result’s &lt;code dir=&quot;auto&quot;&gt;correlationId&lt;/code&gt;. ARCCHR0024, ARCCHR0028 and ARCCHR0033 report most of these at build time. See &lt;a href=&quot;https://blog.cratis.io/when-arc-says-no/&quot;&gt;Part 5&lt;/a&gt; and Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/refusals/&quot;&gt;refusals&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;why-was-my-reducer-refused&quot;&gt;Why was my reducer refused?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Chronicle can’t replay a reducer exactly when it filters its events or depends on a service. A reducer is admitted when it has no event filter and no constructor dependencies other than &lt;code dir=&quot;auto&quot;&gt;ILogger&amp;#x3C;T&gt;&lt;/code&gt;. Remove the filter or the dependencies, read a projection of the same events, or mark the read &lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt; if it’s only context. See &lt;a href=&quot;https://blog.cratis.io/when-arc-says-no/&quot;&gt;Part 5&lt;/a&gt; and Chronicle’s &lt;a href=&quot;https://www.cratis.io/chronicle/read-models/decision-reads/#reducers&quot;&gt;decision reads&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;what-if-my-read-model-is-keyed-by-an-event-property&quot;&gt;What if my read model is keyed by an event property?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;It can’t be guarded. Its events live on other event sources, one per book for example, and a guard watches one source. ARCCHR0024 warns at build time, and under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; the command is refused with a &lt;code dir=&quot;auto&quot;&gt;500&lt;/code&gt;. Append a fact to the entity the model is keyed by, so the command writes one event to each entity in one append, or use a constraint. &lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt; only turns the read back into a snapshot. See &lt;a href=&quot;https://blog.cratis.io/one-rule-two-entities/&quot;&gt;Part 3&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;questions-about-choosing-a-mechanism&quot;&gt;Questions about choosing a mechanism&lt;/h2&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;how-do-i-make-a-value-unique&quot;&gt;How do I make a value unique?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;With a constraint on the event: &lt;code dir=&quot;auto&quot;&gt;[Unique]&lt;/code&gt; on a property for a value, on the event type for “once per entity”. The kernel checks it inside every append, from every writer and every client. A validator can’t do it, and neither can read protection: two members registering the same email are two different keys, and no read of one key sees the other. A constraint is checked per event sequence and per namespace, and it can’t count. See &lt;a href=&quot;https://blog.cratis.io/not-every-rule-needs-a-guarded-read/&quot;&gt;Part 7&lt;/a&gt; and Chronicle’s &lt;a href=&quot;https://www.cratis.io/chronicle/constraints/&quot;&gt;constraints&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;how-do-i-enforce-a-rule-over-two-entities&quot;&gt;How do I enforce a rule over two entities?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Take one read model per entity in the validator, each with &lt;code dir=&quot;auto&quot;&gt;[LookUpBy(nameof(...))]&lt;/code&gt; naming the command property that holds its key, and return one &lt;code dir=&quot;auto&quot;&gt;EventForEventSourceId&lt;/code&gt; per entity from &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt;. Each read guards its own key, both guards are checked with the one atomic append, and if either was violated, neither event is written. Use a separate event type for each entity: a model folds every event of its types, wherever it was appended. See &lt;a href=&quot;https://blog.cratis.io/one-rule-two-entities/&quot;&gt;Part 3&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;whats-the-difference-between-a-per-stream-read-model-and-a-stream-decision&quot;&gt;What’s the difference between a per-stream read model and a stream decision?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;A per-stream read model folds state, a total or a status, from one stream of an entity, such as one account’s &lt;code dir=&quot;auto&quot;&gt;Transactions&lt;/code&gt; for &lt;code dir=&quot;auto&quot;&gt;2026-10&lt;/code&gt;. Declare &lt;code dir=&quot;auto&quot;&gt;[EventStream&amp;#x3C;TSource&gt;(&quot;Transactions&quot;)]&lt;/code&gt; on the model, route the command with &lt;code dir=&quot;auto&quot;&gt;[EventSource&amp;#x3C;TSource&gt;(&quot;Transactions&quot;)]&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;[EventStreamId(&quot;{Month}&quot;)]&lt;/code&gt;, and the guard covers the model’s event types in that stream. A stream decision reads the raw events of the command’s stream and answers “has this happened?”. Any event in that stream after the read conflicts, and the whole stream crosses the wire, so it suits short streams. Use one of them in a command, not both. See &lt;a href=&quot;https://blog.cratis.io/a-limit-for-one-month/&quot;&gt;Part 4&lt;/a&gt; and Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/commands/stream-decisions/&quot;&gt;stream decisions&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;does-an-event-source-definition-or-concurrency-true-make-my-rule-hold&quot;&gt;Does an event source definition, or &lt;code dir=&quot;auto&quot;&gt;concurrency: true&lt;/code&gt;, make my rule hold?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;No. Both narrow the default append check, and that check reads the event source’s tail when the events are appended, after the validator and &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; have decided. It can’t tie the commit to what the decision read. For that you need a constraint, a guarded read, a stream decision, an aggregate or an explicit scope. See &lt;a href=&quot;https://blog.cratis.io/not-every-rule-needs-a-guarded-read/&quot;&gt;Part 7&lt;/a&gt; and Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/faq/#does-an-event-source-definition-make-my-rule-hold&quot;&gt;FAQ&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;why-did-my-command-fail-when-nothing-it-decided-on-changed&quot;&gt;Why did my command fail when nothing it decided on changed?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;The guard is wider than the read you were thinking of. Reads of one event source merge into one guard over the event types of all of them, so a retitle refuses a borrow whose validator also read a title model of the same book. A whole-source read beside a per-stream read widens the guard to every month, reading two months of one stream drops the stream id, and a &lt;code dir=&quot;auto&quot;&gt;Concurrency&lt;/code&gt; declared on the definition with the event source id but not both stream dimensions widens it the same way. A wider guard still includes everything the narrower one watched; it adds conflicts and doesn’t drop any. Mark reads you only use as context &lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt;, and take only the per-stream model when the rule is about one period. ARCCHR0038 reports the combinations it can see. See &lt;a href=&quot;https://blog.cratis.io/a-limit-for-one-month/&quot;&gt;Part 4&lt;/a&gt;, &lt;a href=&quot;https://blog.cratis.io/when-arc-says-no/&quot;&gt;Part 5&lt;/a&gt; and &lt;a href=&quot;https://blog.cratis.io/how-a-guard-is-built/&quot;&gt;Part 10&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;questions-about-chronicle-other-languages-and-dcb&quot;&gt;Questions about Chronicle, other languages and DCB&lt;/h2&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;can-i-use-this-from-kotlin-java-typescript-or-elixir&quot;&gt;Can I use this from Kotlin, Java, TypeScript or Elixir?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Arc’s read protection, command scenarios and analyzers are part of Arc for .NET. Chronicle’s decision reads, the mechanism underneath, are in the .NET and Elixir clients. Constraints and concurrency scopes are in all five Chronicle clients, and the kernel checks a constraint on every append, whichever client sent it. See &lt;a href=&quot;https://blog.cratis.io/not-every-rule-needs-a-guarded-read/&quot;&gt;Part 7&lt;/a&gt; and &lt;a href=&quot;https://blog.cratis.io/decision-reads-without-arc/&quot;&gt;Part 8&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;can-i-get-the-same-guard-without-arc&quot;&gt;Can I get the same guard without Arc?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Yes. In the .NET client, &lt;code dir=&quot;auto&quot;&gt;GetDecisionReads().GetDetached&amp;#x3C;T&gt;(key)&lt;/code&gt; notes the position and folds the key, and &lt;code dir=&quot;auto&quot;&gt;AppendMany(…, guardedBy: [read])&lt;/code&gt; appends with that read as the condition. Check &lt;code dir=&quot;auto&quot;&gt;IsSuccess&lt;/code&gt;, and &lt;code dir=&quot;auto&quot;&gt;GetDecisionConflicts&lt;/code&gt; to tell a lost race from a constraint violation: a conflict is a result, not an exception. Inside an ASP.NET Core request, &lt;code dir=&quot;auto&quot;&gt;IDecisionReads.Get&amp;#x3C;T&gt;&lt;/code&gt; enrolls the read in the request’s unit of work; stage events with &lt;code dir=&quot;auto&quot;&gt;Transactional.Append&lt;/code&gt; and commit with &lt;code dir=&quot;auto&quot;&gt;IUnitOfWorkCompletionFeature.CommitAsync()&lt;/code&gt; before you respond, because the middleware otherwise commits after the response and reports nothing. In Elixir, read with &lt;code dir=&quot;auto&quot;&gt;DecisionReads.get&lt;/code&gt; inside &lt;code dir=&quot;auto&quot;&gt;Chronicle.decide&lt;/code&gt;. See &lt;a href=&quot;https://blog.cratis.io/decision-reads-without-arc/&quot;&gt;Part 8&lt;/a&gt; and Chronicle’s &lt;a href=&quot;https://www.cratis.io/chronicle/read-models/decision-reads/&quot;&gt;decision reads&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;is-this-the-dynamic-consistency-boundary&quot;&gt;Is this the Dynamic Consistency Boundary?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Chronicle supports DCB-style decision models and append conditions within its event-source model. It is not a DCB event store. Each event belongs to one event source, and the event source ID, event source type, event stream type and event stream ID play the part of tags, with one value each. Custom tags take no part in consistency, and a fact about two entities is two events in one atomic append. See &lt;a href=&quot;https://blog.cratis.io/decision-reads-without-arc/&quot;&gt;Part 8&lt;/a&gt;, Einar’s &lt;a href=&quot;https://blog.cratis.io/dcb-but-not-dcb/&quot;&gt;DCB, but not DCB&lt;/a&gt; and &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/chronicle/&quot;&gt;DCB in Chronicle&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;questions-about-testing-and-seeing-the-guard&quot;&gt;Questions about testing and seeing the guard&lt;/h2&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;how-do-i-test-that-a-rule-holds&quot;&gt;How do I test that a rule holds?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Put a competing write between the command’s read and its commit. In Arc, &lt;code dir=&quot;auto&quot;&gt;new CommandScenario&amp;#x3C;T&gt;()&lt;/code&gt;, seed events with &lt;code dir=&quot;auto&quot;&gt;Given.ForEventSource(id).Events(...)&lt;/code&gt;, queue the competitor with &lt;code dir=&quot;auto&quot;&gt;AppendConcurrently(id, ...)&lt;/code&gt;, and assert &lt;code dir=&quot;auto&quot;&gt;ShouldHaveValidationErrorBecauseOf(ValidationResultReason.ConcurrencyViolation)&lt;/code&gt; and an empty &lt;code dir=&quot;auto&quot;&gt;AppendedEvents&lt;/code&gt;. The scenario runs the command in the mode it declares, in its project or on the command, so under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; the test fails, which is what it’s for. Seed events rather than pinned read models: a guarded read never sees a pinned instance. See &lt;a href=&quot;https://blog.cratis.io/testing-a-race/&quot;&gt;Part 9&lt;/a&gt; and Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/scenarios/testing/&quot;&gt;Test the race&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;how-do-i-see-what-a-commit-guarded&quot;&gt;How do I see what a commit guarded?&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;In code that calls Chronicle directly with read protection enforced on the unit of work, call &lt;code dir=&quot;auto&quot;&gt;IUnitOfWork.GetAppendConditions()&lt;/code&gt; after the commit. It returns one condition per guarded event source, with its event types, stream values, position and the origins behind it. Assert on the origins and the number of conditions rather than on their text. See &lt;a href=&quot;https://blog.cratis.io/how-a-guard-is-built/&quot;&gt;Part 10&lt;/a&gt; and Chronicle’s &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/how-guards-are-derived/#see-what-a-commit-guarded&quot;&gt;How guards are derived&lt;/a&gt;.&lt;/p&gt;
&lt;aside aria-label=&quot;Where to start&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;Where to start&lt;/p&gt;&lt;div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A new application:&lt;/strong&gt; &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; in the project, and each “may this proceed” rule in a validator that takes the read model (&lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;Part 2&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An application that already runs:&lt;/strong&gt; &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; first, fix what it reports, then &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; per project (&lt;a href=&quot;https://blog.cratis.io/turning-read-protection-on/&quot;&gt;Part 6&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A rule that isn’t about state on a key:&lt;/strong&gt; the decision guide above, then &lt;a href=&quot;https://blog.cratis.io/not-every-rule-needs-a-guarded-read/&quot;&gt;Part 7&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A refusal you don’t understand:&lt;/strong&gt; &lt;a href=&quot;https://blog.cratis.io/when-arc-says-no/&quot;&gt;Part 5&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code that calls Chronicle directly:&lt;/strong&gt; &lt;a href=&quot;https://blog.cratis.io/decision-reads-without-arc/&quot;&gt;Part 8&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A test that should show the rule holds:&lt;/strong&gt; &lt;a href=&quot;https://blog.cratis.io/testing-a-race/&quot;&gt;Part 9&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A guard that conflicts more than you expect:&lt;/strong&gt; &lt;a href=&quot;https://blog.cratis.io/how-a-guard-is-built/&quot;&gt;Part 10&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;div&gt;&lt;h2 id=&quot;the-series&quot;&gt;The series&lt;/h2&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.cratis.io/the-bug-you-never-see/&quot;&gt;The bug you never see&lt;/a&gt;. Check-then-act decisions, why two requests can both pass the check, and what the database defaults do about it.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;The read model said yes&lt;/a&gt;. A command that checks a read model and then appends, and the project setting that makes the check hold at the append.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.cratis.io/one-rule-two-entities/&quot;&gt;One rule, two entities, one append&lt;/a&gt;. Two reads, one fact for each entity, and one atomic append.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.cratis.io/a-limit-for-one-month/&quot;&gt;A limit for one account and one month&lt;/a&gt;. Guarding a decision on one stream, so last month’s activity doesn’t conflict with today’s.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.cratis.io/when-arc-says-no/&quot;&gt;When Arc says no&lt;/a&gt;. The two kinds of refusal, what each means, and what the caller and the UI should do.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.cratis.io/turning-read-protection-on/&quot;&gt;Turning read protection on in an application that already runs&lt;/a&gt;. Measuring first, fixing what it finds, and switching on per project.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.cratis.io/not-every-rule-needs-a-guarded-read/&quot;&gt;Not every rule needs a guarded read&lt;/a&gt;. Constraints, aggregates, explicit scopes, stream decisions, repair and hints, and the choices that fail silently.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.cratis.io/decision-reads-without-arc/&quot;&gt;The same guard without Arc: decision reads and append conditions&lt;/a&gt;. The Chronicle calls underneath, and how they map to the Dynamic Consistency Boundary.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.cratis.io/testing-a-race/&quot;&gt;Testing a decision against a race&lt;/a&gt;. Putting a competing write between a command’s read and its commit.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.cratis.io/how-a-guard-is-built/&quot;&gt;How a guard is built, merged and widened&lt;/a&gt;. Predicting exactly which events make a command fail.&lt;/li&gt;
&lt;li&gt;Questions and a decision guide. This page.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;&lt;h2 id=&quot;where-the-docs-are&quot;&gt;Where the docs are&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;For Arc commands, start at &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/&quot;&gt;Choosing how a command’s rule holds&lt;/a&gt;. From there, &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/getting-started/&quot;&gt;Getting started&lt;/a&gt; turns &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; for a first command, &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/adopting/&quot;&gt;Adopting read protection&lt;/a&gt; is the path from &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; through &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;, &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/refusals/&quot;&gt;Refusals&lt;/a&gt; lists every error with its fix, &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/how-it-works/&quot;&gt;How it works&lt;/a&gt; derives and merges guards, &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/pitfalls/&quot;&gt;Pitfalls&lt;/a&gt; covers what fails silently, and the &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/faq/&quot;&gt;FAQ&lt;/a&gt; has more short answers.&lt;/p&gt;
&lt;p&gt;For Chronicle without Arc, start at &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/&quot;&gt;Dynamic Consistency Boundary&lt;/a&gt;, which has a reading order. &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/choosing/&quot;&gt;Choosing how a rule holds&lt;/a&gt; picks the mechanism, &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/chronicle/&quot;&gt;DCB in Chronicle&lt;/a&gt; says what maps and what doesn’t, &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/how-guards-are-derived/&quot;&gt;How guards are derived&lt;/a&gt; and &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/limits/&quot;&gt;Costs and limits&lt;/a&gt; go into the detail, and its &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/faq/&quot;&gt;questions and answers&lt;/a&gt; cover the client’s side. The API pages are &lt;a href=&quot;https://www.cratis.io/chronicle/read-models/decision-reads/&quot;&gt;Decision reads&lt;/a&gt; and &lt;a href=&quot;https://www.cratis.io/chronicle/read-models/read-protection/&quot;&gt;Read protection&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Read protection as described here needs Arc 22.108.0 or later and Chronicle 19.68.0 or later; per-stream read models need Chronicle 19.71.0 or later; decision reads need a Chronicle server of 19.0.0 or later.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;Previous: &lt;a href=&quot;https://blog.cratis.io/how-a-guard-is-built/&quot;&gt;Part 10 — How a guard is built, merged and widened&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>arc</category><category>chronicle</category><category>concurrency</category><category>constraints</category><category>event-sourcing</category></item><item><title>How a guard is built, merged and widened · Decisions that hold, Part 10</title><link>https://blog.cratis.io/how-a-guard-is-built/</link><guid isPermaLink="true">https://blog.cratis.io/how-a-guard-is-built/</guid><description>A guard is a position in the log and a filter. This part takes one apart: where the position and the filter come from, what a second read does to them, how an explicit scope and declared concurrency join in, and how to print what a commit actually guarded.</description><pubDate>Fri, 13 Nov 2026 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://blog.cratis.io/the-bug-you-never-see/&quot;&gt;Decisions that hold&lt;/a&gt; · Part 10 of 11&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Every part of this series so far has leaned on the same object. A validator reads &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; and the command’s append carries a guard. A monthly limit reads one stream of an account and the guard covers that month. A test puts a competing event between the read and the commit and the guard refuses the commit. I’ve described what each guard covers, but not how it’s put together.&lt;/p&gt;
&lt;p&gt;A guard is an append condition: a position in the event log plus a filter. The kernel checks it atomically with the append and rejects the append if any event that matches the filter was appended after the position. Everything in this part is about where the position and the filter come from, what happens when a command has more than one source of them, and how to print the result so you don’t have to take my word for any of it.&lt;/p&gt;
&lt;p&gt;The examples assume read protection is On, as in new Cratis applications (see &lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;Part 2&lt;/a&gt;). Under On, Arc drives the Chronicle machinery shown here for every command. The code below drives it directly, because that’s where you can print the guard.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;print-the-guard-first&quot;&gt;Print the guard first&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Chronicle’s unit of work can report what it sent with the append. Under a read-protection frame, &lt;code dir=&quot;auto&quot;&gt;GetAppendConditions()&lt;/code&gt; returns one &lt;code dir=&quot;auto&quot;&gt;AppendCondition&lt;/code&gt; per guarded event source after the commit:&lt;/p&gt;
&lt;starlight-tabs data-sync-key=&quot;language&quot;&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-0&quot; id=&quot;tab-0-0&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-1&quot; id=&quot;tab-0-1&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Kotlin&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-2&quot; id=&quot;tab-0-2&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-3&quot; id=&quot;tab-0-3&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-4&quot; id=&quot;tab-0-4&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Elixir&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-0&quot; aria-labelledby=&quot;tab-0-0&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Auditing&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSequences&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Execution&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AccountId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MoneyWithdrawn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;decimal&lt;/span&gt;&lt;span&gt;&lt;span&gt; Amount&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// Counts the withdrawals in the stream the read is scoped to.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Passive&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;FromEvent&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;MoneyWithdrawn&lt;/span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MonthlyWithdrawals&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Count&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;MoneyWithdrawn&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Count&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ShowTheGuard&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;IReadOnlyList&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;AppendCondition&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Withdraw&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IEventStore&lt;/span&gt;&lt;span&gt;&lt;span&gt; eventStore&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;AccountId&lt;/span&gt;&lt;span&gt;&lt;span&gt; account&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; unitOfWork &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;UnitOfWork&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;eventStore&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;UnitOfWorkManager&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Begin&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;CorrelationId&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;New&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; frame &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;unitOfWork&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EnforceReadProtection&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; owner &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;unitOfWork&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ClaimDecisionReadCommitOwnership&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// Account, stream type &quot;Transactions&quot;, stream id &quot;2026-10&quot;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;eventStore&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;GetDecisionReads&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;GetFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;MonthlyWithdrawals&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;unitOfWork&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;account&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;2026-10&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;unitOfWork&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AddEvent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSequenceId&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Log&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;account&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MoneyWithdrawn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Causation&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Unknown&lt;/span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventStreamType&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventStreamId&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;2026-10&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;unitOfWork&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;CommitAsOwner&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;owner&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// One AppendCondition per guarded event source. Print it to see what the commit guarded.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;unitOfWork&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;GetAppendConditions&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-1&quot; aria-labelledby=&quot;tab-0-1&quot; role=&quot;tabpanel&quot; tabindex=&quot;0&quot; hidden&gt;&lt;p&gt;The Kotlin client does not have decision reads yet.&lt;/p&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-2&quot; aria-labelledby=&quot;tab-0-2&quot; role=&quot;tabpanel&quot; tabindex=&quot;0&quot; hidden&gt;&lt;p&gt;The Java client does not have decision reads yet.&lt;/p&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-3&quot; aria-labelledby=&quot;tab-0-3&quot; role=&quot;tabpanel&quot; tabindex=&quot;0&quot; hidden&gt;&lt;p&gt;The TypeScript client does not have decision reads yet.&lt;/p&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-4&quot; aria-labelledby=&quot;tab-0-4&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;SeeTheGuardMoneyWithdrawn&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;see-the-guard-money-withdrawn&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;amount&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# Counts the withdrawals in the stream the read is scoped to.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;SeeTheGuardMonthlyWithdrawals&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;passive&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nil&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;count&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;SeeTheGuardMoneyWithdrawn&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;event_source_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;],&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;count&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;count&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;SeeTheGuardShowTheGuard&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;DecisionReads&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;UnitOfWork&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;SeeTheGuardMonthlyWithdrawals&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;withdraw&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;account_id&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;unit_of_work &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;UnitOfWork&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;begin&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;# Account, stream type &quot;Transactions&quot;, stream id &quot;2026-10&quot;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;ok&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;_read&lt;/span&gt;&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;DecisionReads&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;SeeTheGuardMonthlyWithdrawals&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; account_id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;2026-10&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;# One concurrency scope per guarded event source. Inspect it to see what a commit would guard.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;guards &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;UnitOfWork&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get_decision_reads&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;unit_of_work&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;UnitOfWork&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;rollback&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;unit_of_work&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;guards&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;starlight-tabs-restore&gt;&lt;/starlight-tabs-restore&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;The first three lines of &lt;code dir=&quot;auto&quot;&gt;Withdraw&lt;/code&gt; and the &lt;code dir=&quot;auto&quot;&gt;CommitAsOwner&lt;/code&gt; call are what Arc does for a command under On: begin the unit of work, turn read protection on for the whole invocation, claim the right to commit, and commit as that owner at the end. Read protection is part of Arc for .NET. The Elixir tab works differently: it inspects the decision reads enrolled in the unit of work before anything is committed, rather than the conditions a commit sent.&lt;/p&gt;
&lt;p&gt;With one earlier withdrawal in October already in the log, at position 0, &lt;code dir=&quot;auto&quot;&gt;ToString()&lt;/code&gt; on the single condition prints:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;guard BankAccount-7: types=[MoneyWithdrawn], streamType=Transactions, streamId=2026-10, after 0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Read it left to right. &lt;code dir=&quot;auto&quot;&gt;BankAccount-7&lt;/code&gt; is the event source, whose events count. &lt;code dir=&quot;auto&quot;&gt;types=[…]&lt;/code&gt; lists the event type ids that count. For a .NET &lt;code dir=&quot;auto&quot;&gt;[EventType]&lt;/code&gt; record without an explicit id, that’s the type name. &lt;code dir=&quot;auto&quot;&gt;streamType&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;streamId&lt;/code&gt; narrow it to one stream of the source. &lt;code dir=&quot;auto&quot;&gt;after 0&lt;/code&gt; is the position: an event that matches everything before it and lands after position 0 rejects the append. On an empty log the boundary prints as &lt;code dir=&quot;auto&quot;&gt;no matching event&lt;/code&gt; instead, which is how “create it only if nothing like it exists yet” holds.&lt;/p&gt;
&lt;p&gt;The condition also says where it came from. &lt;code dir=&quot;auto&quot;&gt;Origins&lt;/code&gt; is &lt;code dir=&quot;auto&quot;&gt;[ProtectedRead, DefaultRouting]&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;Reads&lt;/code&gt; is &lt;code dir=&quot;auto&quot;&gt;[MonthlyWithdrawals &apos;BankAccount-7&apos;]&lt;/code&gt;: the read gave the guard its filter and position, and it replaces the ordinary optimistic check for an append to that source. &lt;code dir=&quot;auto&quot;&gt;DefaultRouting&lt;/code&gt; only records that the append’s routing was taken into account; it adds nothing to the filter. A source the command reads but doesn’t append to carries only &lt;code dir=&quot;auto&quot;&gt;ProtectedRead&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-parts-of-a-guard&quot;&gt;The parts of a guard&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Every guard has the same four parts. What changes is who supplies them:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Part&lt;/th&gt;
&lt;th&gt;Decision read&lt;/th&gt;
&lt;th&gt;Explicit scope&lt;/th&gt;
&lt;th&gt;Event source definition&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Event source&lt;/td&gt;
&lt;td&gt;The key you read&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;WithEventSourceId&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The event’s own source, when the definition declares the event source id&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Event types&lt;/td&gt;
&lt;td&gt;The types the model folds, including the types that remove it&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;WithEventType&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;None. Any type counts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Source type, stream type, stream id&lt;/td&gt;
&lt;td&gt;Only for a stream-scoped read, with the values you pass&lt;/td&gt;
&lt;td&gt;Whatever you set on the builder&lt;/td&gt;
&lt;td&gt;The dimensions the definition declares&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Position&lt;/td&gt;
&lt;td&gt;The log’s tail, taken before the fold&lt;/td&gt;
&lt;td&gt;The sequence number you captured&lt;/td&gt;
&lt;td&gt;The tail, read when you append&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Only the decision read takes the position before it reads the facts it decides on. That ordering is the whole trick. The client asks the kernel for the tail, then folds the key’s events. An event that lands during the fold, or after it, is after the position, so it conflicts. Take the tail after the fold instead and an event that arrives in between is in nobody’s guard.&lt;/p&gt;
&lt;p&gt;The position is the tail of the whole log, not of the key. With &lt;code dir=&quot;auto&quot;&gt;MemberRegistered&lt;/code&gt; for &lt;code dir=&quot;auto&quot;&gt;member-1&lt;/code&gt; at position 0 and one for &lt;code dir=&quot;auto&quot;&gt;member-2&lt;/code&gt; at position 1, a read of &lt;code dir=&quot;auto&quot;&gt;MemberLoans&lt;/code&gt; for &lt;code dir=&quot;auto&quot;&gt;member-1&lt;/code&gt; gives:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;guard member-1: types=[MemberRegistered,LoanTaken,LoanReturned], after 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;That’s harmless: the filter decides what counts, and nothing for &lt;code dir=&quot;auto&quot;&gt;member-1&lt;/code&gt; arrived after position 1. What the filter means in practice, with competing events appended between that read and the commit:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Competing event&lt;/th&gt;
&lt;th&gt;Commit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;MemberRenamed&lt;/code&gt; for &lt;code dir=&quot;auto&quot;&gt;member-1&lt;/code&gt;, a type the model doesn’t fold&lt;/td&gt;
&lt;td&gt;Succeeds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;LoanTaken&lt;/code&gt; for &lt;code dir=&quot;auto&quot;&gt;member-2&lt;/code&gt;, another source&lt;/td&gt;
&lt;td&gt;Succeeds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;LoanTaken&lt;/code&gt; for &lt;code dir=&quot;auto&quot;&gt;member-1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rejected, nothing written&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The rejection is a &lt;code dir=&quot;auto&quot;&gt;ConcurrencyViolation&lt;/code&gt; with the event source and the expected and actual sequence numbers. It doesn’t say which event caused it (&lt;a href=&quot;https://github.com/Cratis/Chronicle/issues/4926&quot;&gt;Chronicle#4926&lt;/a&gt; tracks that), and Chronicle doesn’t re-run your decision. A model that doesn’t exist yet is guarded the same way: the read of an unknown &lt;code dir=&quot;auto&quot;&gt;member-9&lt;/code&gt; returns no instance, and a &lt;code dir=&quot;auto&quot;&gt;MemberRegistered&lt;/code&gt; for &lt;code dir=&quot;auto&quot;&gt;member-9&lt;/code&gt; that arrives before the commit rejects it.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;several-reads&quot;&gt;Several reads&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;A command often reads more than once. The unit of work collects every read, any explicit scope you pass, and the routing of the events you append, and merges them per event source when you commit. Only routing a definition declares joins the merge; ordinary routing leaves the reads’ guard as it is:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/how-guards-merge.fv4wVraN_1WyQcW.webp&quot; alt=&quot;A diagram titled How a commit’s guard is assembled. On the left, a frame labeled In the unit of work holds three cards: Decision reads, key plus types, tail taken first; Explicit scope, your scope, must cover reads; Definition, declared routing, its dimensions. Arrows from all three lead to a tall card labeled Per source, Merge, union of types, and from there to a card labeled Per source, One guard, with the append. A band underneath reads One condition fails: nothing in the batch is written.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2400&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Everything a commit is guarded by is collected in the unit of work and merged per event source.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Reads of different sources stay separate. Reading &lt;code dir=&quot;auto&quot;&gt;MemberLoans&lt;/code&gt; for both &lt;code dir=&quot;auto&quot;&gt;member-1&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;member-2&lt;/code&gt; gives two conditions, checked in the same atomic append, so a conflict on either one rejects the whole batch:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;guard member-1: types=[MemberRegistered,LoanTaken,LoanReturned], after 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;guard member-2: types=[MemberRegistered,LoanTaken,LoanReturned], after 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Reads of the same source merge into one condition. The event types are the union, the position is the earliest of the reads, and each stream value survives only if the reads agree on it. Here are the two cases that surprise people, both printed from a commit under a read-protection frame. October’s and November’s &lt;code dir=&quot;auto&quot;&gt;MonthlyWithdrawals&lt;/code&gt; for the same account:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;guard BankAccount-7: types=[MoneyWithdrawn], streamType=Transactions, after 0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The stream ids differ, so the stream id is gone. A withdrawal in December now rejects the commit, though neither read looked at December. October’s &lt;code dir=&quot;auto&quot;&gt;MonthlyWithdrawals&lt;/code&gt; beside a whole-account &lt;code dir=&quot;auto&quot;&gt;AccountBalance&lt;/code&gt;, which folds deposits too:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;guard BankAccount-7: types=[MoneyWithdrawn,MoneyDeposited], after 0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The whole-account read has no stream, so the stream type and id are both gone, and the types are the union of both models.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/what-two-reads-become.ByiuGyia_Z1yHexW.webp&quot; alt=&quot;A diagram titled What a second read does, in three rows. One read of MonthlyWithdrawals for 2026-10 gives a guard covering 2026-10, MoneyWithdrawn. A second read of the same model for 2026-11 gives a guard covering any month, MoneyWithdrawn. A second read of the whole account, AccountBalance, gives a guard covering any stream, with MoneyDeposited added. A band underneath reads A merged guard only gets wider.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2300&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;What a second read of the same account does to the guard.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That’s the rule to remember: merging only widens. The merged condition covers everything either read would have caught, so a second read can add conflicts but can’t hide one. Outside a read-protection frame, for example &lt;code dir=&quot;auto&quot;&gt;AppendMany(guardedBy: reads)&lt;/code&gt;, the stream values are kept only when both match and are otherwise both dropped; under a frame each value is kept or dropped on its own. If a rule really depends on two streams, read the whole source once instead, so the guard says what it covers. In an Arc command, &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/code-analysis/arcchr0038/&quot;&gt;ARCCHR0038&lt;/a&gt; points out a per-stream read whose guard another read will widen.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;an-explicit-scope-beside-a-read&quot;&gt;An explicit scope beside a read&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;You can still pass your own concurrency scope for a source you also read. Chronicle doesn’t guess whether it’s enough. Under a frame it checks that the scope covers the read: its source, source type, stream type and stream id are each unset or equal to the read’s, its event types are empty or a superset, and its position is the same or earlier. A scope on the whole account, captured before the October read, covers it, and becomes the condition:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;guard BankAccount-7: any type, after 0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Its &lt;code dir=&quot;auto&quot;&gt;Origins&lt;/code&gt; are &lt;code dir=&quot;auto&quot;&gt;[ProtectedRead, Explicit, DefaultRouting]&lt;/code&gt;. A scope that is narrower than the read is refused at commit. A scope on &lt;code dir=&quot;auto&quot;&gt;Transactions/2026-10&lt;/code&gt; beside a whole-account &lt;code dir=&quot;auto&quot;&gt;AccountBalance&lt;/code&gt; read fails with &lt;code dir=&quot;auto&quot;&gt;ExplicitScopeDoesNotCoverReads&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;The command returns an exact concurrency scope for &apos;BankAccount-7&apos; that does not watch what it read: AccountBalance &apos;BankAccount-7&apos;. Widen the scope and capture its boundary before reading.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Outside a frame, combining a decision read and an explicit scope on one source is refused outright with &lt;code dir=&quot;auto&quot;&gt;DecisionReadConflictsWithConcurrencyScope&lt;/code&gt;. In Arc, a stream decision is an explicit scope, so a stream decision beside a whole-source read of the same source is refused for the same reason: the stream is narrower than the read. &lt;a href=&quot;https://blog.cratis.io/a-limit-for-one-month/&quot;&gt;Part 4&lt;/a&gt; met the same refusal from the other side: a stream decision beside a per-stream validator, whose scope is captured after the validator’s read.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;declared-concurrency-on-a-definition&quot;&gt;Declared concurrency on a definition&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;An event source definition can declare which dimensions guard every append to it. This one makes every event in one month of a ledger conflict with every other event in that month:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSources&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// Every event in one month of a ledger conflicts with every other event in that month.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Ledger&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventStream&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Concurrency &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyDimensions&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyDimensions&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventStreamType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyDimensions&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventStreamId&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LedgerEventSource&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IEventSource&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LedgerPosted&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;decimal&lt;/span&gt;&lt;span&gt;&lt;span&gt; Amount&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Read a per-month model of &lt;code dir=&quot;auto&quot;&gt;LedgerPosted&lt;/code&gt; for source type &lt;code dir=&quot;auto&quot;&gt;Ledger&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;Transactions/2026-10&lt;/code&gt;, then stage the posting without the definition’s routing. The read passes the source type along with the stream type and stream id, so the guard is the read’s own, with origins &lt;code dir=&quot;auto&quot;&gt;[ProtectedRead, DefaultRouting]&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;guard BankAccount-7: types=[LedgerPosted], sourceType=Ledger, streamType=Transactions, streamId=2026-10, after 0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Stage the same posting through &lt;code dir=&quot;auto&quot;&gt;LedgerEventSource&lt;/code&gt;, and under a frame the declared dimensions merge into the read’s guard:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;guard BankAccount-7: any type, streamType=Transactions, streamId=2026-10, after 0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The origins change from &lt;code dir=&quot;auto&quot;&gt;DefaultRouting&lt;/code&gt; to &lt;code dir=&quot;auto&quot;&gt;DeclaredRouting&lt;/code&gt;. The declared dimensions are kept only where they equal the read’s, so the month stays. The event types become any type, because the definition says every event in the month counts. The source type isn’t among the declared dimensions, so it’s dropped. The position is still the read’s. Any event in October now rejects the commit, not only a posting.&lt;/p&gt;
&lt;p&gt;Arc follows the same rule under On: it doesn’t build the routing scope itself, it hands the declared dimensions to Chronicle, which merges them at commit.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;The definition declares&lt;/th&gt;
&lt;th&gt;What it does to a read’s guard&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Nothing, or &lt;code dir=&quot;auto&quot;&gt;None&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dimensions that include the event source id&lt;/td&gt;
&lt;td&gt;Merged into the read’s guard. Event types become any type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dimensions without the event source id&lt;/td&gt;
&lt;td&gt;A separate guard, not tied to the read. It doesn’t protect the state you read&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;That’s correct when the month really is the consistency boundary, such as a ledger, a numbering sequence or an approval stream, where every writer should see every other. For anything else it only adds conflicts. ARCCHR0038 also reports a declared &lt;code dir=&quot;auto&quot;&gt;Concurrency&lt;/code&gt; that includes the event source id without both stream dimensions, because it widens a per-stream guard to the whole source.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;aggregates-and-stream-decisions&quot;&gt;Aggregates and stream decisions&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Two more dependencies supply guards in Arc, and both fit the same shape:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dependency&lt;/th&gt;
&lt;th&gt;Guard&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Aggregate root&lt;/td&gt;
&lt;td&gt;Taken when the aggregate is rehydrated: its event source and the event types it handles, from the tail at that moment. An aggregate and a protected read of the same source are refused&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stream decision&lt;/td&gt;
&lt;td&gt;An explicit scope taken when the stream is read: the routed stream, any event type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fresh identifier check&lt;/td&gt;
&lt;td&gt;An “expect no matching event” guard on the new id&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;&lt;h2 id=&quot;what-a-guard-cannot-see&quot;&gt;What a guard cannot see&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;A guard compares events appended after a position with a filter, so anything that isn’t an appended event matching that filter is outside it: revisions and redactions, writers without a guard, projection definitions changed elsewhere, other sequences and stores. &lt;a href=&quot;https://blog.cratis.io/decision-reads-without-arc/&quot;&gt;Part 8&lt;/a&gt; and &lt;a href=&quot;https://blog.cratis.io/testing-a-race/&quot;&gt;Part 9&lt;/a&gt; list these in full. Two details follow from the anatomy. Chronicle refuses &lt;code dir=&quot;auto&quot;&gt;Revise&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;Redact&lt;/code&gt; inside a read-protection frame, so a protected command can’t do them to itself (&lt;a href=&quot;https://github.com/Cratis/Chronicle/issues/4900&quot;&gt;Chronicle#4900&lt;/a&gt; tracks a kernel check for other processes). And a command that reads but appends nothing has no guard at all: &lt;code dir=&quot;auto&quot;&gt;GetAppendConditions()&lt;/code&gt; is empty.&lt;/p&gt;
&lt;p&gt;Guards also have a cost shape worth knowing. Each guarded read folds the key’s history of the model’s types, every time, and folds of one model type are served through one projection per type in the kernel, so they are expected to queue behind each other across keys and tenants. Chronicle’s &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/limits/&quot;&gt;costs and limits&lt;/a&gt; page has the one measurement published so far, with its environment. Keep guarded models flat and keys short-lived.&lt;/p&gt;
&lt;aside aria-label=&quot;What to do when&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;What to do when&lt;/p&gt;&lt;div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A guard is wider than you expected:&lt;/strong&gt; print it. Look for a second read of the same source, a whole-source read beside a per-stream one, or declared &lt;code dir=&quot;auto&quot;&gt;Concurrency&lt;/code&gt; on the definition.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You return an explicit scope and also read the source:&lt;/strong&gt; the scope must cover the read and be captured no later than it, or the commit fails with &lt;code dir=&quot;auto&quot;&gt;ExplicitScopeDoesNotCoverReads&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You want to assert the guard in a test of Chronicle-direct code:&lt;/strong&gt; call &lt;code dir=&quot;auto&quot;&gt;GetAppendConditions()&lt;/code&gt; after the commit and assert on the count and each condition’s &lt;code dir=&quot;auto&quot;&gt;Origins&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You’re tempted to declare &lt;code dir=&quot;auto&quot;&gt;Concurrency&lt;/code&gt; on a definition:&lt;/strong&gt; do it for ledgers, numbering and approval streams only.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A rule needs two streams of one source:&lt;/strong&gt; read the whole source once rather than two streams.&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Chronicle’s &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/how-guards-are-derived/&quot;&gt;How guards are derived&lt;/a&gt; page has the full merge tables, Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/how-it-works/&quot;&gt;How read protection works&lt;/a&gt; shows what Arc does for each command, and &lt;a href=&quot;https://www.cratis.io/chronicle/read-models/read-protection/&quot;&gt;read protection&lt;/a&gt; documents the frame API. The last part of the series collects the questions that come up most and a guide to which mechanism a rule needs.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The examples need Chronicle 19.68.0 or later. With Arc, read protection needs Arc 22.108.0 or later.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;Previous: &lt;a href=&quot;https://blog.cratis.io/testing-a-race/&quot;&gt;Part 09 — Testing a decision against a race&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>arc</category><category>chronicle</category><category>concurrency</category><category>event-sourcing</category></item><item><title>Testing a decision against a race · Decisions that hold, Part 9</title><link>https://blog.cratis.io/testing-a-race/</link><guid isPermaLink="true">https://blog.cratis.io/testing-a-race/</guid><description>A test that runs one command at a time passes with a plain read too. One line in an Arc command scenario puts a competing write between the read and the commit, and turns &apos;it works&apos; into &apos;it still holds when someone else is faster&apos;.</description><pubDate>Wed, 11 Nov 2026 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://blog.cratis.io/the-bug-you-never-see/&quot;&gt;Decisions that hold&lt;/a&gt; · Part 09 of 11&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.cratis.io/the-bug-you-never-see/&quot;&gt;Part 1&lt;/a&gt; said the race is invisible in the tests most of us write, because they run one request at a time. Parts 2 to 8 showed how Arc and Chronicle guard a decision. This part is about the test that shows the guard is there: the command reads, someone else writes, and the command must not commit.&lt;/p&gt;
&lt;p&gt;The examples assume read protection is On, as in new Cratis applications (see &lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;Part 2&lt;/a&gt;). They use the library from Part 2: &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; folded from &lt;code dir=&quot;auto&quot;&gt;CopyAdded&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;BookBorrowed&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;BookReturned&lt;/code&gt;, and &lt;code dir=&quot;auto&quot;&gt;BorrowBook&lt;/code&gt; with a validator that takes &lt;code dir=&quot;auto&quot;&gt;BookStock?&lt;/code&gt;. Command scenarios and read protection are part of Arc for .NET. The general tour of command scenarios is in &lt;a href=&quot;https://blog.cratis.io/testing-with-arc-and-chronicle/&quot;&gt;&lt;em&gt;Testing with Arc and Chronicle&lt;/em&gt;&lt;/a&gt;; this post assumes it.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;a-test-that-passes-once&quot;&gt;A test that passes once&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;These are the tests I’d write first for &lt;code dir=&quot;auto&quot;&gt;BorrowBook&lt;/code&gt;: one where a copy is on the shelf, and one where it isn’t.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Testing&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Testing&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Validation&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Xunit&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;when_borrowing_a_book&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;with_a_copy_on_the_shelf_it_is_lent&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; scenario &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CommandScenario&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; isbn &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;isbn-1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Given&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ForEventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopyAdded&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; result &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Execute&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;NewGuid&lt;/span&gt;&lt;span&gt;())));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldBeSuccessful&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldHaveAppendedEvent&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;with_no_copy_on_the_shelf_it_is_refused&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; scenario &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CommandScenario&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; isbn &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;isbn-1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Given&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ForEventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopyAdded&lt;/span&gt;&lt;span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;NewGuid&lt;/span&gt;&lt;span&gt;())));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; result &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Execute&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;NewGuid&lt;/span&gt;&lt;span&gt;())));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldHaveValidationErrorBecauseOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ValidationResultReason&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Rule&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Assert&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Empty&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AppendedEvents&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Both are worth having. The second asserts the reason, not just that the command failed. &lt;code dir=&quot;auto&quot;&gt;ShouldHaveValidationErrors()&lt;/code&gt; passes for almost any rejection: a rule, a constraint, a race, a validator that threw. It fails on purpose when the only results are dependencies that couldn’t be resolved, because then no rule ran at all: a validator whose read model the test forgot to seed is never built, and the test would keep passing with the rule deleted. &lt;code dir=&quot;auto&quot;&gt;ShouldHaveValidationErrorBecauseOf(ValidationResultReason.Rule)&lt;/code&gt; passes only when the validator’s rule said no.&lt;/p&gt;
&lt;p&gt;Neither test says anything about a race. Both pass with read protection &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;, where the validator’s read is a plain snapshot that guards nothing. A test that never puts another writer between the read and the commit can’t tell a guarded read from an unguarded one.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;a-competitor-between-the-read-and-the-commit&quot;&gt;A competitor between the read and the commit&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;This is the race from Part 2 as a test. One copy is on the shelf, another member borrows it after our command has read the stock, and our command must not commit:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Testing&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Testing&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Validation&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Xunit&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;when_another_member_borrows_the_last_copy_first&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;it_is_refused_and_nothing_is_written&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; scenario &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CommandScenario&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; isbn &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;isbn-1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Given&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ForEventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopyAdded&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AppendConcurrently&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;NewGuid&lt;/span&gt;&lt;span&gt;())));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; result &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Execute&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;NewGuid&lt;/span&gt;&lt;span&gt;())));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldHaveValidationErrorBecauseOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ValidationResultReason&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ConcurrencyViolation&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Assert&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Equal&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;ReadChanged&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Assert&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Single&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ValidationResults&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ReasonDetail&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Assert&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Empty&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AppendedEvents&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Line by line:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;Given.ForEventSource(isbn).Events(new CopyAdded())&lt;/code&gt; seeds the book’s history into the scenario’s event log. The validator’s &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; is folded from that log, so it sees one copy and the rule passes.&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;AppendConcurrently(isbn, ...)&lt;/code&gt; queues a competing event. The scenario doesn’t append it now. It appends it while the command runs: after the validator has read and &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; has returned, and before the command’s unit of work commits. That’s the window two real requests race in.&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;Execute&lt;/code&gt; runs the command through the same pipeline as production. The commit finds a &lt;code dir=&quot;auto&quot;&gt;BookBorrowed&lt;/code&gt; for this book after the position the read took, and refuses the append.&lt;/li&gt;
&lt;li&gt;The assertions check the reason (&lt;code dir=&quot;auto&quot;&gt;ConcurrencyViolation&lt;/code&gt;), the detail (&lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt;, which tells a changed read from one that couldn’t be read completely), and that nothing from the command was written. &lt;code dir=&quot;auto&quot;&gt;AppendedEvents&lt;/code&gt; holds the command’s own appends that succeeded. The competitor’s event stays in the log, but it isn’t in that list.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The validation result carries the same message a caller gets:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;BookStock &apos;isbn-1&apos; changed after BorrowBook read it. Nothing from this command was written; submit it again.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/where-the-competitor-lands.De0T5tyM_Z1kULmg.webp&quot; alt=&quot;A diagram titled Where the competitor lands. Inside a frame labeled One command, as in production, four cards run left to right: Read, BookStock at p; Decide, validator and Handle; Commit, guarded by p; and a red card, 400 ReadChanged. Below, a card labeled Given, CopyAdded, seeded first, points to Read. A card labeled Competitor, BookBorrowed for isbn-1, appended after the read, points to Commit. A band reads The competitor lands after p. The commit sees it.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1900&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The seeded events are there before the read. The competitor lands between the read and the commit.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is the test that changes when the mode changes. Compile the same command with read protection &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; and run the same test: the command succeeds, its &lt;code dir=&quot;auto&quot;&gt;BookBorrowed&lt;/code&gt; is appended next to the competitor’s, and the assertion on &lt;code dir=&quot;auto&quot;&gt;ConcurrencyViolation&lt;/code&gt; fails. That failure is the test doing its job. It says the rule isn’t guarded.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;what-the-scenario-sets-up-for-you&quot;&gt;What the scenario sets up for you&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;There’s no setup in that test beyond &lt;code dir=&quot;auto&quot;&gt;new CommandScenario&amp;#x3C;BorrowBook&gt;()&lt;/code&gt;. The scenario looks at the command first. When it runs under read protection &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;, is marked &lt;code dir=&quot;auto&quot;&gt;[ProtectedDecision]&lt;/code&gt;, or takes a decision dependency (&lt;code dir=&quot;auto&quot;&gt;DecisionRead&amp;#x3C;T&gt;&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;IDecisionReads&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;IStreamReads&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;StreamDecision&lt;/code&gt;, or a per-stream read model), the scenario uses one real in-process Chronicle event log for everything: the seeded events, the guarded reads, the competitor and the command’s commit. The read and the commit see the same history, which is what makes the race real.&lt;/p&gt;
&lt;p&gt;Older tests may call &lt;code dir=&quot;auto&quot;&gt;UseDecisionReads()&lt;/code&gt; to get that log. It isn’t needed anymore. It’s hidden from IntelliSense and kept so those tests compile.&lt;/p&gt;
&lt;p&gt;The mode comes from the assembly that declares the command, or from &lt;code dir=&quot;auto&quot;&gt;[ReadProtection(...)]&lt;/code&gt; on the command, as in production. The test project doesn’t set anything. If the command’s project says &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, the test runs under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Two things change in that mode:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;scenario.EventScenario&lt;/code&gt; throws &lt;code dir=&quot;auto&quot;&gt;EventScenarioUnavailableInDecisionMode&lt;/code&gt;. It belongs to a separate log that the command’s reads would never see. Seed with &lt;code dir=&quot;auto&quot;&gt;Given.ForEventSource(...).Events(...)&lt;/code&gt;. &lt;code dir=&quot;auto&quot;&gt;scenario.EventLog&lt;/code&gt; points at the shared log, and it holds everything: seeds, competitors and commits.&lt;/li&gt;
&lt;li&gt;Seeding on a route, &lt;code dir=&quot;auto&quot;&gt;Given.ForEventSource(...).OnRoute(route).Events(...)&lt;/code&gt;, needs this log. Outside it, routed seeding throws.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; selects the same log, but it doesn’t add a guard. A command under &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; returns what it would return under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;, so the race test fails under &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; just as it does under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;. Measure reports what &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; would do; it doesn’t do it. Test the command in the mode it runs in.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;seed-events-not-read-models&quot;&gt;Seed events, not read models&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Command scenarios can also pin a read model instead of deriving it from events:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Given&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ForEventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; that doesn’t do what it looks like. A guarded read always folds the event log, as it does in production, and never sees a pinned instance. With that pin and no events, the validator gets &lt;code dir=&quot;auto&quot;&gt;null&lt;/code&gt; and the command is refused with “No copies of this book are available.” A pinned instance serves only the reads that don’t guard the decision, such as a read marked &lt;code dir=&quot;auto&quot;&gt;[Unprotected]&lt;/code&gt;. For a &lt;code dir=&quot;auto&quot;&gt;[ProtectedDecision]&lt;/code&gt; command that takes the model as a &lt;code dir=&quot;auto&quot;&gt;DecisionRead&amp;#x3C;T&gt;&lt;/code&gt;, pinning it throws &lt;code dir=&quot;auto&quot;&gt;PinnedReadModelCannotProvideDecisionToken&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So seed the events that produce the state. For a guarded read they’re the only way to supply it, and they test the projection as well.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;two-keys&quot;&gt;Two keys&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Part 3’s &lt;code dir=&quot;auto&quot;&gt;BorrowBook&lt;/code&gt; reads two models, &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; for the book and &lt;code dir=&quot;auto&quot;&gt;MemberLoans&lt;/code&gt; for the member, and appends one event to each in one batch. Each read guards its own key, so a competing write on either key must refuse the whole borrow. This test competes on the member: two loans are taken, a third arrives after the read, and the borrow would have been the fourth.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Testing&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Testing&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Validation&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Xunit&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;when_the_member_takes_another_loan_first&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;the_whole_borrow_is_refused&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; scenario &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CommandScenario&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; isbn &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;isbn-1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; member &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;member-1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Given&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ForEventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopyAdded&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Given&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ForEventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;member&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LoanTaken&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;isbn-2&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LoanTaken&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;isbn-3&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AppendConcurrently&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;member&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LoanTaken&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;isbn-4&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; result &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Execute&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;member&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldHaveValidationErrorBecauseOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ValidationResultReason&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ConcurrencyViolation&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Assert&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Empty&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AppendedEvents&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The message names the model and the key that changed:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;MemberLoans &apos;member-1&apos; changed after BorrowBook read it. Nothing from this command was written; submit it again.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Neither the book’s &lt;code dir=&quot;auto&quot;&gt;BookBorrowed&lt;/code&gt; nor the member’s &lt;code dir=&quot;auto&quot;&gt;LoanTaken&lt;/code&gt; is written. Write the same test with the competitor on the book, a &lt;code dir=&quot;auto&quot;&gt;BookBorrowed&lt;/code&gt; for &lt;code dir=&quot;auto&quot;&gt;isbn-1&lt;/code&gt;, and it’s refused too. One test per key you read is the way to find a key that isn’t guarded, for example a model that is read through a key other than the one you expected.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;one-month&quot;&gt;One month&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Part 4’s withdrawal limit reads &lt;code dir=&quot;auto&quot;&gt;MonthlyWithdrawals&lt;/code&gt; from one month’s stream. The competitor has to land on the same route for the test to mean anything, so seed and compete on the route, not just the account:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Testing&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Testing&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Validation&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Xunit&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;when_another_withdrawal_lands_while_withdrawing&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;in_the_same_month_it_is_refused&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; scenario &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CommandScenario&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Withdraw&lt;/span&gt;&lt;span&gt;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; account &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AccountId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;account-1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; october &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventRoutes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;For&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BankAccountEventSource&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;WithStreamId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;2026-10&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Given&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ForEventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;account&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;OnRoute&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;october&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MoneyWithdrawn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;4000m&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AppendConcurrently&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;account&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;october&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MoneyWithdrawn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;500m&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; result &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Execute&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Withdraw&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;account&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;2026-10&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;500m&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldHaveValidationErrorBecauseOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ValidationResultReason&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ConcurrencyViolation&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Assert&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Empty&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AppendedEvents&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;in_another_month_it_goes_through&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; scenario &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CommandScenario&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Withdraw&lt;/span&gt;&lt;span&gt;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; account &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AccountId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;account-1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; transactions &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventRoutes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;For&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BankAccountEventSource&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Given&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ForEventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;account&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;OnRoute&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;transactions&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithStreamId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;2026-10&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MoneyWithdrawn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;4000m&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AppendConcurrently&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;account&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;transactions&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithStreamId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;2026-11&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MoneyWithdrawn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;500m&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; result &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Execute&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Withdraw&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;account&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;2026-10&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;500m&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldBeSuccessful&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;scenario&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldHaveAppendedEvent&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Withdraw&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;MoneyWithdrawn&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;account&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;scenario.EventRoutes&lt;/code&gt; resolves a route from the event source definitions the scenario discovered, so &lt;code dir=&quot;auto&quot;&gt;For&amp;#x3C;BankAccountEventSource&gt;(&quot;Transactions&quot;)&lt;/code&gt; is the same stream type the command is routed to, and &lt;code dir=&quot;auto&quot;&gt;WithStreamId(&quot;2026-10&quot;)&lt;/code&gt; is the month. &lt;code dir=&quot;auto&quot;&gt;OnRoute&lt;/code&gt; seeds there, and the &lt;code dir=&quot;auto&quot;&gt;AppendConcurrently&lt;/code&gt; overload that takes a route makes the competitor land there.&lt;/p&gt;
&lt;p&gt;The second test is the one people skip. It checks that the guard isn’t wider than the rule: a withdrawal in November doesn’t touch October’s total, so it mustn’t refuse an October withdrawal. Part 4 showed how a whole-account read next to the monthly one widens the guard to every month. A test like this is how you’d notice. The same goes for the library: a borrow of another book, or a &lt;code dir=&quot;auto&quot;&gt;BookRenamed&lt;/code&gt; on the same book, which &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; doesn’t fold, should leave the command alone.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;without-arc&quot;&gt;Without Arc&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;When you call Chronicle directly, as in Part 8, the race test has the same shape without a scenario: take the decision read, append a competing event, then do the guarded append and check that it was refused. Chronicle’s &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/scenarios/#test-the-race&quot;&gt;Test the race&lt;/a&gt; scenario shows it in C# and Elixir.&lt;/p&gt;
&lt;p&gt;If the code runs in a unit of work with read protection enforced, you can also check what was guarded. After the commit, &lt;code dir=&quot;auto&quot;&gt;unitOfWork.GetAppendConditions()&lt;/code&gt; (namespace &lt;code dir=&quot;auto&quot;&gt;Cratis.Chronicle.Transactions&lt;/code&gt;) returns one &lt;code dir=&quot;auto&quot;&gt;AppendCondition&lt;/code&gt; per guarded source, with its event types, stream values, position and the origins behind it. Assert on the origins and the number of conditions rather than on their text. &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/how-guards-are-derived/#see-what-a-commit-guarded&quot;&gt;See what a commit guarded&lt;/a&gt; in Chronicle’s docs has the example. Part 10 is about how those conditions are built.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;what-a-green-race-test-does-not-show&quot;&gt;What a green race test does not show&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;A race test checks one interleaving: one competitor, at one point, after the read and before the commit. It shows the guard covers that event on that key. It doesn’t show:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Timing or load.&lt;/strong&gt; The log is Chronicle’s in-process store for tests, not a Chronicle server or its storage. A green test says nothing about how the guard behaves under contention or what it costs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Writers that don’t guard their own decision.&lt;/strong&gt; Your command detects a matching event from any writer. A command elsewhere that reads plainly, under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;, through &lt;code dir=&quot;auto&quot;&gt;[Unprotected]&lt;/code&gt; or with an immediate append, can still break the rule with its own decision.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What’s outside every guard.&lt;/strong&gt; &lt;code dir=&quot;auto&quot;&gt;Revise&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;Redact&lt;/code&gt;, projection definitions changed by another process, services, other databases and other event sequences.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The mode in production.&lt;/strong&gt; The test runs in the mode compiled into the command’s assembly. A runtime cap, &lt;code dir=&quot;auto&quot;&gt;ReadProtection:MaximumMode&lt;/code&gt;, can lower it on a host. Part 6 covers that.&lt;/li&gt;
&lt;/ul&gt;
&lt;aside aria-label=&quot;What to do when&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;What to do when&lt;/p&gt;&lt;div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The command runs under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;:&lt;/strong&gt; a plain &lt;code dir=&quot;auto&quot;&gt;new CommandScenario&amp;#x3C;T&gt;()&lt;/code&gt;, events seeded with &lt;code dir=&quot;auto&quot;&gt;Given.ForEventSource(...).Events(...)&lt;/code&gt;, a competitor with &lt;code dir=&quot;auto&quot;&gt;AppendConcurrently&lt;/code&gt;, and &lt;code dir=&quot;auto&quot;&gt;ShouldHaveValidationErrorBecauseOf(ValidationResultReason.ConcurrencyViolation)&lt;/code&gt; plus an empty &lt;code dir=&quot;auto&quot;&gt;AppendedEvents&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The test pins read models with &lt;code dir=&quot;auto&quot;&gt;.ReadModel(...)&lt;/code&gt;:&lt;/strong&gt; seed the events instead. A guarded read never sees a pinned instance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An old test seeds through &lt;code dir=&quot;auto&quot;&gt;scenario.EventScenario&lt;/code&gt;:&lt;/strong&gt; move the seeding to &lt;code dir=&quot;auto&quot;&gt;Given.ForEventSource(...).Events(...)&lt;/code&gt;. &lt;code dir=&quot;auto&quot;&gt;EventScenario&lt;/code&gt; throws under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The command reads two keys:&lt;/strong&gt; one race test per key. Each must refuse the whole command.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The read is per stream:&lt;/strong&gt; seed and compete on the same route, and add a test where a competitor on another stream id goes through.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The command runs under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;:&lt;/strong&gt; the race test fails, because nothing is guarded. That’s the answer the test is there to give.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The code calls Chronicle directly:&lt;/strong&gt; read, compete, append with the guard; under enforced read protection, assert on &lt;code dir=&quot;auto&quot;&gt;GetAppendConditions()&lt;/code&gt; after the commit.&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;The reference is Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/scenarios/testing/&quot;&gt;Test the race&lt;/a&gt;, and &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/testing/chronicle/#protected-decision-scenarios&quot;&gt;Testing Chronicle commands&lt;/a&gt; covers the scenario’s decision mode in full, including how reads that don’t guard the decision are resolved.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The examples need Arc 22.108.0 or later and Chronicle 19.71.0 or later.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;Previous: &lt;a href=&quot;https://blog.cratis.io/decision-reads-without-arc/&quot;&gt;Part 08 — The same guard without Arc: decision reads and append conditions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>arc</category><category>chronicle</category><category>concurrency</category><category>event-sourcing</category><category>validation</category></item><item><title>The same guard without Arc: decision reads and append conditions · Decisions that hold, Part 8</title><link>https://blog.cratis.io/decision-reads-without-arc/</link><guid isPermaLink="true">https://blog.cratis.io/decision-reads-without-arc/</guid><description>Under Arc&apos;s read protection is one Chronicle call you can make yourself: note where the log was, fold the state, and append only if nothing it depended on arrived since. This part writes that guard by hand, and says exactly what it is in DCB terms and what it is not.</description><pubDate>Mon, 09 Nov 2026 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://blog.cratis.io/the-bug-you-never-see/&quot;&gt;Decisions that hold&lt;/a&gt; · Part 08 of 11&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Parts 2 to 7 let Arc do the work. A command takes a read model, read protection is On, and the read guards the command’s append without any code that mentions a guard. Those examples assume read protection is On, as in new Cratis applications (see &lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;Part 2&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Not every decision runs as an Arc command. A minimal API endpoint, an MVC controller, a background worker or an Elixir service talks to Chronicle directly, and there nothing enrolls a read for you. The mechanism underneath Arc is a Chronicle API, and you can call it yourself. This part does that, and then uses the result to say concretely what Chronicle’s guard is in the terms of the Dynamic Consistency Boundary (DCB), and what it is not.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;what-arc-was-doing-for-you&quot;&gt;What Arc was doing for you&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Arc’s read protection is a host for Chronicle’s decision reads. For each command under On, it does three things:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;In an Arc command under On&lt;/th&gt;
&lt;th&gt;In Chronicle’s API&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A read-model parameter is read fresh&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;IDecisionReads.GetFor&amp;#x3C;T&gt;(unit, key)&lt;/code&gt;: note the log position, fold the key, enroll the read as a guard in the command’s unit of work&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The events &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; returns are written&lt;/td&gt;
&lt;td&gt;Staged in the unit and appended with every enrolled guard in one call&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A lost race comes back as a 400 with &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The unit’s commit fails, and &lt;code dir=&quot;auto&quot;&gt;GetDecisionConflicts()&lt;/code&gt; names the read model and key&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Without Arc, those three are yours: take the read as a decision read, attach it to the append, and check the result before you answer the caller. Chronicle’s &lt;a href=&quot;https://www.cratis.io/chronicle/read-models/read-protection/#how-arc-uses-this-api&quot;&gt;read protection page&lt;/a&gt; has the full mapping.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;a-decision-read-and-a-guarded-append&quot;&gt;A decision read and a guarded append&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The smallest form guards one append. A workshop has a fixed number of places, and a booking may only be made while one is free. &lt;a href=&quot;https://www.cratis.io/chronicle/read-models/decision-reads/&quot;&gt;Decision reads&lt;/a&gt; exist in the .NET and Elixir clients:&lt;/p&gt;
&lt;starlight-tabs data-sync-key=&quot;language&quot;&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-0&quot; id=&quot;tab-0-0&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-1&quot; id=&quot;tab-0-1&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Kotlin&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-2&quot; id=&quot;tab-0-2&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-3&quot; id=&quot;tab-0-3&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Elixir&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-4&quot; id=&quot;tab-0-4&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-0&quot; aria-labelledby=&quot;tab-0-0&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSequences&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkshopId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkshopOpened&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Places&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PlaceBooked&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Attendee&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PlaceCancelled&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Attendee&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// The decision model: a flat projection with an Id, keyed by the event source.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;FromEvent&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;WorkshopOpened&lt;/span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkshopPlaces&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;WorkshopOpened&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;nameof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;WorkshopOpened&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Places&lt;/span&gt;&lt;span&gt;&lt;span&gt;))]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Total&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Increment&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PlaceBooked&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Decrement&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PlaceCancelled&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Booked&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookPlace&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;bool&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IEventStore&lt;/span&gt;&lt;span&gt;&lt;span&gt; eventStore&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;WorkshopId&lt;/span&gt;&lt;span&gt;&lt;span&gt; workshop&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; attendee&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// 1. The read notes the log position, then folds the workshop&apos;s events.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; read &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;eventStore&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;GetDecisionReads&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;GetDetached&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;WorkshopPlaces&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReadModelKey&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;workshop&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;read&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;not&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; places &lt;/span&gt;&lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;places&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Booked&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;places&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Total&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// 2. The append carries the read as its guard. A later PlaceBooked, PlaceCancelled or&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;//    WorkshopOpened for this workshop rejects it and nothing is written.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; result &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;eventStore&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventLog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AppendMany&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventForEventSourceId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;workshop&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PlaceBooked&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;attendee&lt;/span&gt;&lt;span&gt;))],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;guardedBy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;read&lt;/span&gt;&lt;span&gt;]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IsSuccess&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-1&quot; aria-labelledby=&quot;tab-0-1&quot; role=&quot;tabpanel&quot; tabindex=&quot;0&quot; hidden&gt;&lt;p&gt;The Kotlin client does not have decision reads yet.&lt;/p&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-2&quot; aria-labelledby=&quot;tab-0-2&quot; role=&quot;tabpanel&quot; tabindex=&quot;0&quot; hidden&gt;&lt;p&gt;The Java client does not have decision reads yet.&lt;/p&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-3&quot; aria-labelledby=&quot;tab-0-3&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WorkshopOpened&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;workshop-opened&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;places&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PlaceBooked&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;place-booked&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;attendee&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PlaceCancelled&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;place-cancelled&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;attendee&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# The decision model: a flat projection keyed by the event source.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WorkshopPlaces&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nil&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;total&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;booked&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WorkshopOpened&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;event_source_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;total&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;places&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PlaceBooked&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;add&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;booked&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PlaceCancelled&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;subtract&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;booked&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BookPlace&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSequences&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventLog&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.{&lt;/span&gt;&lt;span&gt;DecisionConflict&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;DecisionReads&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PlaceBooked&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WorkshopPlaces&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;handle&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;workshop_id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; attendee&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;result &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;decide&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;fn&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_unit_of_work&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;# 1. The read notes the log position, folds the workshop&apos;s events and enrolls&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;#    itself as the guard of the unit of work.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;ok&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; read&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;DecisionReads&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;WorkshopPlaces&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; workshop_id&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;case&lt;/span&gt;&lt;span&gt;&lt;span&gt; read&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;instance &lt;/span&gt;&lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;WorkshopPlaces&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&lt;span&gt;total&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; total&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;booked&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; booked&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;when&lt;/span&gt;&lt;span&gt; booked &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; total &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;# 2. The append is buffered and committed with the guard. A later booking,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;#    cancellation or opening for this workshop rejects the whole commit.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;ok&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventLog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;append&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;workshop_id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; %&lt;/span&gt;&lt;/span&gt;&lt;span&gt;PlaceBooked&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&lt;span&gt;attendee&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; attendee&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;booked&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;full&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;case&lt;/span&gt;&lt;span&gt; result &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;ok&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;booked&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;ok&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;full&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; %&lt;/span&gt;&lt;/span&gt;&lt;span&gt;DecisionConflict&lt;/span&gt;&lt;span&gt;&lt;span&gt;{}}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;_reason&lt;/span&gt;&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-4&quot; aria-labelledby=&quot;tab-0-4&quot; role=&quot;tabpanel&quot; tabindex=&quot;0&quot; hidden&gt;&lt;p&gt;The TypeScript client does not have decision reads yet.&lt;/p&gt;&lt;/div&gt;&lt;starlight-tabs-restore&gt;&lt;/starlight-tabs-restore&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;GetDetached&lt;/code&gt; does two things in order. It notes the position of the event log’s tail, and then it folds &lt;code dir=&quot;auto&quot;&gt;WorkshopPlaces&lt;/code&gt; for that workshop from the event log in a fresh projection session. It does not use the stored read model, which can lag and has no position. What comes back is the state (&lt;code dir=&quot;auto&quot;&gt;read.Instance&lt;/code&gt;) and the guard (&lt;code dir=&quot;auto&quot;&gt;read&lt;/code&gt; itself), and &lt;code dir=&quot;auto&quot;&gt;guardedBy: [read]&lt;/code&gt; hands the guard to the append. The kernel then rejects the append if an event of a type the model folds (&lt;code dir=&quot;auto&quot;&gt;WorkshopOpened&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;PlaceBooked&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;PlaceCancelled&lt;/code&gt;) was appended for this workshop after the noted position.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/decision-model-append-condition.C6a0rBTp_F55FY.webp&quot; alt=&quot;Four numbered steps from top to bottom: note the log position, fold ws-1 as the decision model, decide that Booked is less than Total, append with the condition. The condition for ws-1 lists WorkshopOpened, PlaceBooked and PlaceCancelled after the position from step one. Below it, two outcomes: a PlaceBooked for ws-1 arriving after step one rejects the append and nothing is written; a PlaceBooked for ws-2 does not, because another key is not watched.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2400&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The fold is what you decide on. The key, the model’s event types and the noted position are what the append is checked against.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Three details matter when you write this yourself.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;An absent model is guarded too.&lt;/strong&gt; If nothing has opened the workshop, &lt;code dir=&quot;auto&quot;&gt;Instance&lt;/code&gt; is &lt;code dir=&quot;auto&quot;&gt;null&lt;/code&gt; and the guard expects no matching event at all, so a &lt;code dir=&quot;auto&quot;&gt;WorkshopOpened&lt;/code&gt; that lands before the append rejects it. The example returns &lt;code dir=&quot;auto&quot;&gt;false&lt;/code&gt; in that case anyway, but a create-if-absent rule depends on it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A conflict is a result, not an exception.&lt;/strong&gt; &lt;code dir=&quot;auto&quot;&gt;AppendMany&lt;/code&gt; returns an &lt;code dir=&quot;auto&quot;&gt;AppendManyResult&lt;/code&gt; with &lt;code dir=&quot;auto&quot;&gt;IsSuccess&lt;/code&gt; set to &lt;code dir=&quot;auto&quot;&gt;false&lt;/code&gt;, and &lt;code dir=&quot;auto&quot;&gt;result.GetDecisionConflicts([read])&lt;/code&gt; returns one conflict that names &lt;code dir=&quot;auto&quot;&gt;WorkshopPlaces&lt;/code&gt; and the key. &lt;code dir=&quot;auto&quot;&gt;IsSuccess&lt;/code&gt; is also &lt;code dir=&quot;auto&quot;&gt;false&lt;/code&gt; for a constraint violation, so ask for the conflicts when you need to tell the two apart.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nothing is retried.&lt;/strong&gt; Chronicle does not re-run your decision. The fold itself makes up to three attempts if events arrive while it folds, but once you have the value, a lost race means: read again, decide again, or tell the caller.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Events on other keys, or events of a type the model does not fold, such as a hypothetical &lt;code dir=&quot;auto&quot;&gt;WorkshopRenamed&lt;/code&gt;, leave the append alone. The guard is as narrow as the model.&lt;/p&gt;
&lt;p&gt;The Elixir client reads inside &lt;code dir=&quot;auto&quot;&gt;Chronicle.decide&lt;/code&gt;. &lt;code dir=&quot;auto&quot;&gt;DecisionReads.get&lt;/code&gt; enrolls the read in the unit of work that &lt;code dir=&quot;auto&quot;&gt;decide&lt;/code&gt; opens, &lt;code dir=&quot;auto&quot;&gt;EventLog.append&lt;/code&gt; buffers the event in that unit, and the unit commits with the guard when the function returns. A lost race comes back as &lt;code dir=&quot;auto&quot;&gt;{:error, %DecisionConflict{}}&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;inside-a-request&quot;&gt;Inside a request&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;GetDetached&lt;/code&gt; suits code where the read and the append sit next to each other. In a web request they often don’t: the read happens in one service, the append in another. In the .NET client, &lt;code dir=&quot;auto&quot;&gt;IDecisionReads.Get&amp;#x3C;T&gt;&lt;/code&gt; enrolls the read in the request’s unit of work instead of returning a detached guard, and every event staged in that unit is appended with the guard when it commits.&lt;/p&gt;
&lt;p&gt;A member may hold at most three loans. As a minimal API endpoint, with the loan count as the decision model:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LoanTaken&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Isbn&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MemberLoans&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Increment&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;LoanTaken&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Active&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AspNetCore&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSequences&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Microsoft&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AspNetCore&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Builder&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Microsoft&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AspNetCore&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Http&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;TakeLoanRequest&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Isbn&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LoanEndpoints&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Map&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;WebApplication&lt;/span&gt;&lt;span&gt;&lt;span&gt; app&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;MapPost&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;/members/{memberId}/loans&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;memberId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;TakeLoanRequest&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;HttpContext&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;http&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IDecisionReads&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;reads&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IEventLog&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;eventLog&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;loans&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;reads&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Get&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;MemberLoans&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;memberId&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;loans&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Active&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Results&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;UnprocessableEntity&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;The member has reached the loan limit.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;eventLog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Transactional&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;memberId&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LoanTaken&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;unit&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;http&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Features&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Get&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;IUnitOfWorkCompletionFeature&lt;/span&gt;&lt;span&gt;&gt;()&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;CommitAsync&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;unit&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;GetDecisionConflicts&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Any&lt;/span&gt;&lt;span&gt;())&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Results&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Conflict&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;The member&apos;s loans changed. Nothing was written; read again and decide again.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;unit&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IsSuccess&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Results&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Ok&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Results&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;UnprocessableEntity&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;The loan was not recorded.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Chronicle’s ASP.NET Core middleware begins a unit of work for each request, and &lt;code dir=&quot;auto&quot;&gt;Get&amp;#x3C;T&gt;&lt;/code&gt; needs that ambient unit. &lt;code dir=&quot;auto&quot;&gt;Transactional.Append&lt;/code&gt; stages the event in it. The line that is easy to leave out is the commit. Left alone, the middleware commits the unit after the endpoint has returned, when the response is already on its way, and it reports no concurrency violation to the caller. The caller would see a 200 for a write that was rejected. &lt;code dir=&quot;auto&quot;&gt;IUnitOfWorkCompletionFeature.CommitAsync()&lt;/code&gt; asks the middleware’s owner to commit now, so the endpoint can answer with the outcome, and the middleware does not commit that unit again.&lt;/p&gt;
&lt;p&gt;When another loan for the same member lands between the read and the commit, this endpoint answers 409, and the member’s log has the competing loan and not this one. A member who already holds three gets the 422 before anything is staged. The conflict check comes before &lt;code dir=&quot;auto&quot;&gt;IsSuccess&lt;/code&gt; because &lt;code dir=&quot;auto&quot;&gt;IsSuccess&lt;/code&gt; is also &lt;code dir=&quot;auto&quot;&gt;false&lt;/code&gt; for a constraint violation. And the 409 carries a message, not the conflicts themselves: in Chronicle 19.73 and earlier, a &lt;code dir=&quot;auto&quot;&gt;DecisionConflict&lt;/code&gt; holds the read model’s &lt;code dir=&quot;auto&quot;&gt;Type&lt;/code&gt;, which System.Text.Json refuses to serialize, so &lt;code dir=&quot;auto&quot;&gt;Results.Conflict(unit.GetDecisionConflicts())&lt;/code&gt; fails while it writes the response, on exactly the path you wanted to report. Map conflicts to your own response shape.&lt;/p&gt;
&lt;p&gt;One mistake undoes it quietly: a plain &lt;code dir=&quot;auto&quot;&gt;eventLog.Append(...)&lt;/code&gt; in the same request is written immediately and bypasses the guard. A controller action uses the same calls, with &lt;code dir=&quot;auto&quot;&gt;HttpContext.Features&lt;/code&gt; instead of the &lt;code dir=&quot;auto&quot;&gt;http&lt;/code&gt; parameter; Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/scenarios/chronicle-direct/&quot;&gt;Chronicle used directly&lt;/a&gt; page has both. In Elixir, &lt;code dir=&quot;auto&quot;&gt;Chronicle.decide&lt;/code&gt; commits when its function returns, so the outcome is known while you can still choose the response.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;in-dcb-terms&quot;&gt;In DCB terms&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;DCB, as the &lt;a href=&quot;https://dcb.events/specification/&quot;&gt;specification&lt;/a&gt; describes it, gives every event a set of tags. A decision builds its state, the decision model, from a query: event types (any of them) and tags (all of them). When it appends, it passes an append condition: fail if an event matching that query was stored after the position the decision read up to. One event can carry several tags, so a fact about a student and a course is one event that both decisions see.&lt;/p&gt;
&lt;p&gt;Chronicle has the same two parts, a decision model and an append condition, but not the tags. Each event belongs to exactly one event source. The role of the tags is played by four values on every event, each with exactly one value: the event source ID, the event source type, the event stream type and the event stream ID. For the workshop read above, the query is “&lt;code dir=&quot;auto&quot;&gt;WorkshopOpened&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;PlaceBooked&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;PlaceCancelled&lt;/code&gt;, with event source ID &lt;code dir=&quot;auto&quot;&gt;ws-1&lt;/code&gt;”, and the position is the one noted before the fold.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;DCB&lt;/th&gt;
&lt;th&gt;Chronicle&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Decision model&lt;/td&gt;
&lt;td&gt;The state of a decision read: a flat projection keyed by the event source, over a finite set of event types&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query: event types ORed, tags ANDed&lt;/td&gt;
&lt;td&gt;The read model’s event types, and the event source ID plus, where you narrow it, event source type, stream type and stream ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;after&lt;/code&gt;: the position the decision read up to&lt;/td&gt;
&lt;td&gt;The position the decision read notes before it folds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Append condition&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;guardedBy:&lt;/code&gt; on &lt;code dir=&quot;auto&quot;&gt;AppendMany&lt;/code&gt;, or the reads enrolled in a unit of work&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Atomic append across entities&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;AppendMany&lt;/code&gt;, all or nothing across event sources. A unit of work commits as one &lt;code dir=&quot;auto&quot;&gt;AppendMany&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;What DCB can do and Chronicle cannot follows from the one-source-per-event model. One event can’t be tagged with two entities, so a fact about two entities is two events in one atomic &lt;code dir=&quot;auto&quot;&gt;AppendMany&lt;/code&gt;, one per event source. There is no query for “events about both X and Y”. Custom tags are stored and filterable, but take no part in concurrency, so anything the guard must tell apart has to be an event type or one of the four values. Two independent conditions on the same event source are merged into one wider one. A decision read refuses a projection that joins entities or is keyed by something other than the event source. And a guard covers the event log only, not other event sequences.&lt;/p&gt;
&lt;p&gt;Chronicle’s own summary is the sentence I’d keep: it supports DCB-style decision models and append conditions within its event-source model. It is not a DCB event store. Einar’s &lt;a href=&quot;https://blog.cratis.io/dcb-but-not-dcb/&quot;&gt;DCB, but not DCB&lt;/a&gt; argues for naming what you want from DCB instead. The &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/chronicle/&quot;&gt;DCB in Chronicle&lt;/a&gt; page has the full mapping and says when recording one fact as two events is acceptable, and &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/dcb-examples/&quot;&gt;DCB examples in Chronicle&lt;/a&gt; answers each canonical DCB example, including the course subscription with two decision reads and two events.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;when-no-model-fits-tail-first&quot;&gt;When no model fits: tail first&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Some decisions don’t fit an admitted read model: a balance summed from two event types with no projection for it, or a rule over raw events. You can build the same guard by hand. Note the tail first, read the facts after, and append with a concurrency scope from the noted tail. In the .NET client:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSequences&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSequences&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Concurrency&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Microsoft&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AspNetCore&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Http&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ScopeBuilder&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSequences&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Concurrency&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ConcurrencyScopeBuilder&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Deposited&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;decimal&lt;/span&gt;&lt;span&gt;&lt;span&gt; Amount&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Withdrawn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;decimal&lt;/span&gt;&lt;span&gt;&lt;span&gt; Amount&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Withdraw&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;IResult&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IEventLog&lt;/span&gt;&lt;span&gt;&lt;span&gt; eventLog&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;&lt;span&gt; accountId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;decimal&lt;/span&gt;&lt;span&gt;&lt;span&gt; amount&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; tail &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;eventLog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;GetTailSequenceNumber&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;accountId&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; events &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;eventLog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;GetFromSequenceNumber&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;EventSequenceNumber&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;First&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;accountId&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; balance &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Select&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Content&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Sum&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;content &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;switch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;Deposited&lt;/span&gt;&lt;span&gt; deposited &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;deposited&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Amount&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;Withdrawn&lt;/span&gt;&lt;span&gt; withdrawn &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;withdrawn&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Amount&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0m&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;balance&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;amount&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Results&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;UnprocessableEntity&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Insufficient funds.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; scope &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tail&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IsUnavailable&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ScopeBuilder&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;WithEventSourceId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;accountId&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ExpectingNoMatchingEvent&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Build&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyScope&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;tail&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; EventSourceId&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;accountId&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; result &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;eventLog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;accountId&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Withdrawn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;amount&lt;/span&gt;&lt;span&gt;&lt;span&gt;),&lt;/span&gt;&lt;span&gt; concurrencyScope&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;scope&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IsSuccess&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Results&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Ok&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Results&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Conflict&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The order is the guard. With the tail noted before the read, a withdrawal that lands in between is after the scope’s position and rejects the append. Note the tail after the read instead, and that same withdrawal sits before the position: the append succeeds against a balance that no longer holds. When the account has no events yet, the tail is unavailable, and the scope expects no matching event at all.&lt;/p&gt;
&lt;p&gt;This scope is wider than a decision read’s guard: it names no event types, so any event for the account after the tail rejects the append. That is safe, and more conflicts than you need on a busy account. Name the types with &lt;code dir=&quot;auto&quot;&gt;WithEventType&amp;#x3C;T&gt;()&lt;/code&gt; on the builder when only some events matter. The alias at the top is there because in an Arc project &lt;code dir=&quot;auto&quot;&gt;Cratis.Arc.Chronicle.Commands&lt;/code&gt; has a static class called &lt;code dir=&quot;auto&quot;&gt;ConcurrencyScopeBuilder&lt;/code&gt; as well. &lt;a href=&quot;https://blog.cratis.io/not-every-rule-needs-a-guarded-read/&quot;&gt;Part 7&lt;/a&gt; shows a concurrency scope in every Chronicle client.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;results-you-must-check&quot;&gt;Results you must check&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Outside an Arc command, nothing reads the result for you, and every failure on this path is a value.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;Append&lt;/code&gt; returns an &lt;code dir=&quot;auto&quot;&gt;AppendResult&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;AppendMany&lt;/code&gt; an &lt;code dir=&quot;auto&quot;&gt;AppendManyResult&lt;/code&gt;. A concurrency or constraint violation sets &lt;code dir=&quot;auto&quot;&gt;IsSuccess&lt;/code&gt; to &lt;code dir=&quot;auto&quot;&gt;false&lt;/code&gt; and throws nothing, so code that ignores the result reports success whatever happened.&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;GetDecisionConflicts&lt;/code&gt; tells a lost race from a constraint violation and names the read model and key. It does not name the event that conflicted.&lt;/li&gt;
&lt;li&gt;A scope you build yourself without a position fails closed. If it narrows by event source, stream, source type or event types, the client turns it into “no matching event may exist”, so the append is rejected if anything matching is already in the log. Only a scope that narrows nothing is sent unchecked, with a client warning, and &lt;code dir=&quot;auto&quot;&gt;ConcurrencyCheckPerformed&lt;/code&gt; on the result says whether a scope was compared at all, so a skipped check does not look like a passing one. &lt;code dir=&quot;auto&quot;&gt;ConcurrencyOptions.SkipIncompleteExplicitScopes = true&lt;/code&gt; brings back the older skip. Give a scope the tail you noted, or say &lt;code dir=&quot;auto&quot;&gt;ExpectingNoMatchingEvent()&lt;/code&gt; when that is what you mean, as &lt;code dir=&quot;auto&quot;&gt;Withdraw&lt;/code&gt; does.&lt;/li&gt;
&lt;li&gt;The first-append skip belongs to the default check. When Chronicle’s concurrency strategy issues the scope and nothing matching has been appended yet, there is no tail to compare against, and the check is skipped unless &lt;code dir=&quot;auto&quot;&gt;CheckFirstAppendIntoAScope&lt;/code&gt; is on. A decision read of an absent model already expects no matching event.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;limits&quot;&gt;Limits&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;A decision read guards less than it might seem to, and costs more than a plain read.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Only some models can be read this way.&lt;/strong&gt; A flat projection keyed by the event source, or an unfiltered reducer without constructor dependencies other than &lt;code dir=&quot;auto&quot;&gt;ILogger&amp;#x3C;T&gt;&lt;/code&gt;. Joins, children, event-property keys, filtered reducers and other event sequences are refused with &lt;code dir=&quot;auto&quot;&gt;DecisionReadRefused&lt;/code&gt; and a typed reason, before anything is read.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GUID keys must be written the same way everywhere.&lt;/strong&gt; For a model keyed by a GUID, every writer of that event source must use the lowercase canonical form. A writer in another language that formats it differently is outside the guard.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It is a full fold every time.&lt;/strong&gt; Each attempt makes two tail reads, opens a fresh projection session and folds the key’s whole history. The first read of a model type also checks its definition. Keep the keys short-lived. Chronicle’s docs publish &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/limits/#what-a-decision-read-costs&quot;&gt;one measurement with its environment&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What it does not see.&lt;/strong&gt; A revision or redaction of an earlier event does not move the tail, so it does not conflict. Other event sequences, external data, clocks and projection definitions changed by another process are not guarded either. And a guard only protects the decisions that carry it: a writer that appends without one can still break the rule. The rule holds only when every writer that decides on it is guarded, or when it is a &lt;a href=&quot;https://www.cratis.io/chronicle/constraints/&quot;&gt;constraint&lt;/a&gt;, which the kernel checks for every append.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;where-this-goes-next&quot;&gt;Where this goes next&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Everything here is opt-in, append by append. That is the trade: code that calls Chronicle directly chooses each guard, and nothing stops the next change from reading through &lt;code dir=&quot;auto&quot;&gt;IReadModels&lt;/code&gt; and appending without one. Chronicle’s &lt;code dir=&quot;auto&quot;&gt;EnforceReadProtection()&lt;/code&gt; turns that around for a unit of work: inside it, a decision read is enrolled as a guard, a plain read is refused unless you mark it advisory with a reason, and an immediate append is refused. That is the contract Arc enforces for commands under On. Part 10 covers that, and how guards from several reads are merged. Part 9 is first: testing a decision against a competing write.&lt;/p&gt;
&lt;aside aria-label=&quot;What to do when&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;What to do when&lt;/p&gt;&lt;div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;One read, one append:&lt;/strong&gt; &lt;code dir=&quot;auto&quot;&gt;GetDetached&amp;#x3C;T&gt;(key)&lt;/code&gt;, then &lt;code dir=&quot;auto&quot;&gt;AppendMany(…, guardedBy: [read])&lt;/code&gt;, then check &lt;code dir=&quot;auto&quot;&gt;IsSuccess&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;GetDecisionConflicts([read])&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The read and the append are in different places in a request:&lt;/strong&gt; &lt;code dir=&quot;auto&quot;&gt;IDecisionReads.Get&amp;#x3C;T&gt;&lt;/code&gt; in the request’s unit of work, &lt;code dir=&quot;auto&quot;&gt;Transactional.Append&lt;/code&gt;, and &lt;code dir=&quot;auto&quot;&gt;IUnitOfWorkCompletionFeature.CommitAsync()&lt;/code&gt; before you respond.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;In Elixir:&lt;/strong&gt; &lt;code dir=&quot;auto&quot;&gt;DecisionReads.get&lt;/code&gt; inside &lt;code dir=&quot;auto&quot;&gt;Chronicle.decide&lt;/code&gt;, and match on &lt;code dir=&quot;auto&quot;&gt;{:error, %DecisionConflict{}}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No read model fits:&lt;/strong&gt; note the tail, then read, then append with a &lt;code dir=&quot;auto&quot;&gt;ConcurrencyScope&lt;/code&gt; built from that tail.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A value may be claimed once:&lt;/strong&gt; a &lt;a href=&quot;https://www.cratis.io/chronicle/constraints/&quot;&gt;constraint&lt;/a&gt;, not a decision read.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You need every read refused unless it is guarded:&lt;/strong&gt; &lt;code dir=&quot;auto&quot;&gt;EnforceReadProtection()&lt;/code&gt; on the unit of work (Part 10), or an Arc command with read protection On.&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Chronicle’s &lt;a href=&quot;https://www.cratis.io/chronicle/read-models/decision-reads/&quot;&gt;decision reads&lt;/a&gt; page covers the unit-of-work lifecycle, stream-scoped reads and admitted shapes in full. &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/choosing/&quot;&gt;Choosing how a rule holds&lt;/a&gt; compares decision reads with constraints and scopes, and Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/pitfalls/#results-you-must-check-when-you-use-chronicle-directly&quot;&gt;pitfalls&lt;/a&gt; page lists the results to check when you call Chronicle directly.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The .NET examples need Cratis.Chronicle and Cratis.Chronicle.AspNetCore 19.68.0 or later (decision reads themselves arrived in 19.9.0; the scope behaviour described here in 19.68.0), and the Elixir example needs the Elixir client 3.13.0 or later. Decision reads need a Chronicle server of 19.0.0 or later; on servers older than 19.40.1, an append renumbered after a duplicate-sequence collision is not checked again.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;Previous: &lt;a href=&quot;https://blog.cratis.io/not-every-rule-needs-a-guarded-read/&quot;&gt;Part 07 — Not every rule needs a guarded read&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>chronicle</category><category>concurrency</category><category>event-sourcing</category></item><item><title>Careers that remember: introducing the Cratis Cast</title><link>https://blog.cratis.io/careers-that-remember-introducing-the-cratis-cast/</link><guid isPermaLink="true">https://blog.cratis.io/careers-that-remember-introducing-the-cratis-cast/</guid><description>One cast.yaml becomes a personal site that replays your career as events, shows your public GitHub work as it happens, and carries a badge it can&apos;t give itself. The directory at cast.cratis.io is where that badge is checked.</description><pubDate>Mon, 09 Nov 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;“Event Sourcing” on a CV says nothing. It reads the same whether the person skimmed the docs last week or has shipped three systems on Chronicle. A client looking for help can’t tell the two apart, and the people who do the work get little credit for it outside GitHub.&lt;/p&gt;
&lt;p&gt;There’s a second problem we run into all the time. Event sourcing is easier to show than to explain. Most people have never watched a system rebuild its state by replaying facts, and a diagram of an event log doesn’t make them feel it.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://cast.cratis.io&quot;&gt;Cratis Cast&lt;/a&gt; is our answer to both. Its tagline is &lt;em&gt;the people behind the play&lt;/em&gt;, which fits the rest of the family: Screenplay, Stage, Scene, Prologue. Cratis is &lt;em&gt;software that remembers&lt;/em&gt;. Cast is &lt;em&gt;careers that remember&lt;/em&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;one-file-one-site&quot;&gt;One file, one site&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;You run one command and edit one file:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;@cratis/cast@latest&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;my-site&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The scaffolder asks for your GitHub handle, prefills a &lt;code dir=&quot;auto&quot;&gt;cast.yaml&lt;/code&gt; from your public profile, and writes a GitHub Pages workflow that rebuilds the site every hour. The site itself comes from &lt;code dir=&quot;auto&quot;&gt;@cratis/cast&lt;/code&gt;, an Astro integration. Your editor completes and checks &lt;code dir=&quot;auto&quot;&gt;cast.yaml&lt;/code&gt; against its published schema, and engine updates arrive as a version bump.&lt;/p&gt;
&lt;p&gt;What you get is a static site in the Cratis design, with one accent color of your own and light and dark themes. It has sections for what you do now, your writing, your talks and your projects, and a printable CV at &lt;code dir=&quot;auto&quot;&gt;/cv&lt;/code&gt; built from the same data. There’s a terminal behind the backtick key and a command palette on ⌘K or Ctrl+K, because the people who build with Cratis tend to like those.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;a-career-is-an-event-stream&quot;&gt;A career is an event stream&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The part I care most about is the career replay. A career is a sequence of things that happened: you joined a company, took on a role, picked up a skill, left, started something. Cast stores it that way. A visitor presses play, the events fold into a projection in the browser, and the current role, the organizations and the skills rebuild one event at a time.&lt;/p&gt;
&lt;p&gt;That’s event sourcing in about ten seconds, on a page someone opened for a different reason. Nobody has to read an explanation first.&lt;/p&gt;
&lt;p&gt;The numbers on the page come from GitHub, not from you. Merged pull requests, contributions and releases are read from public data on every hourly build and refreshed again in the browser. Private repositories are filtered out at every step.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;a-badge-the-site-cant-claim&quot;&gt;A badge the site can’t claim&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;A personal site is static and its owner controls every byte of it, so anything it says about itself is a claim. Cast is built around that fact.&lt;/p&gt;
&lt;p&gt;There are three tiers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Core&lt;/strong&gt;: the founders and maintainers of Cratis.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Partner&lt;/strong&gt;: consultants and companies Cratis vouches for, people we’ve worked with and would recommend for Cratis work.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contributor&lt;/strong&gt;: anyone with at least one merged pull request in a public repository in the &lt;a href=&quot;https://github.com/Cratis&quot;&gt;Cratis organization&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Core and Partner come only from &lt;a href=&quot;https://github.com/Cratis/Cast/blob/main/Registry/members.yaml&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;Registry/members.yaml&lt;/code&gt;&lt;/a&gt; in the Cast repository, and that file changes only through reviewed pull requests. Contributor is computed from GitHub when a site or the directory builds, and is never listed in the file. &lt;code dir=&quot;auto&quot;&gt;cast.yaml&lt;/code&gt; has no tier field, and the engine rejects one if you add it.&lt;/p&gt;
&lt;p&gt;The badge on a member’s site links to their page on the directory. Cratis builds that page from the registry and live GitHub data, so the directory is the source of truth and the badge is a pointer to it. Badges are SVG images you can embed in a GitHub README, an email signature or anywhere else, and each one links back to its verification page.&lt;/p&gt;
&lt;p&gt;A tier says what someone’s relationship to Cratis is. It isn’t a certification, and it doesn’t come with program benefits, discounts or referrals.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-directory&quot;&gt;The directory&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://cast.cratis.io&quot;&gt;cast.cratis.io&lt;/a&gt; lists the people behind the play. For each Core and Partner member it renders a full profile in the Cratis design from their &lt;code dir=&quot;auto&quot;&gt;/cast.json&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That file is an open format with a published JSON Schema, and a site doesn’t need to be built with Cast to publish one. My own site, &lt;a href=&quot;https://www.woksin.com&quot;&gt;www.woksin.com&lt;/a&gt;, is a custom build that publishes &lt;code dir=&quot;auto&quot;&gt;/cast.json&lt;/code&gt;, and the directory turns it into &lt;a href=&quot;https://cast.cratis.io/woksin/&quot;&gt;my Cast profile&lt;/a&gt;. Contributors get a profile built from public GitHub data.&lt;/p&gt;
&lt;p&gt;Every Cast site also publishes &lt;code dir=&quot;auto&quot;&gt;/resume.json&lt;/code&gt; in the &lt;a href=&quot;https://jsonresume.org/&quot;&gt;JSON Resume&lt;/a&gt; format and an &lt;code dir=&quot;auto&quot;&gt;/llms.txt&lt;/code&gt;. People, the directory and AI agents read the same data, and nobody has to scrape a page to get it.&lt;/p&gt;
&lt;p&gt;Today the Core tier is Einar Ingebrigtsen, Co-founder and CTO, and me, Co-founder and Chief Architect. There are no Partners yet. The directory already shows the verified Contributors.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;try-it&quot;&gt;Try it&lt;/h2&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Scaffold a site: &lt;code dir=&quot;auto&quot;&gt;npm create @cratis/cast@latest my-site&lt;/code&gt;, then fill in &lt;code dir=&quot;auto&quot;&gt;cast.yaml&lt;/code&gt; and push.&lt;/li&gt;
&lt;li&gt;Browse the directory at &lt;a href=&quot;https://cast.cratis.io&quot;&gt;cast.cratis.io&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;See a full profile at &lt;a href=&quot;https://cast.cratis.io/woksin/&quot;&gt;cast.cratis.io/woksin&lt;/a&gt;, and press play.&lt;/li&gt;
&lt;li&gt;Read the code at &lt;a href=&quot;https://github.com/Cratis/Cast&quot;&gt;github.com/Cratis/Cast&lt;/a&gt;. It’s MIT licensed.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;how-to-join&quot;&gt;How to join&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Contributor.&lt;/strong&gt; Get a pull request merged in any public Cratis repository. The next build of the directory, and of your Cast site if you have one, shows the badge. There’s nothing to apply for.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Partner.&lt;/strong&gt; Open a pull request that adds you to &lt;a href=&quot;https://github.com/Cratis/Cast/blob/main/Registry/members.yaml&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;Registry/members.yaml&lt;/code&gt;&lt;/a&gt;, and say in it how you work with Cratis. We review it, may ask to talk first, and merge it only when we can vouch for the work. Not everyone who asks becomes a Partner. If you point the entry at a site that publishes &lt;code dir=&quot;auto&quot;&gt;/cast.json&lt;/code&gt;, the directory renders your full profile; without one it builds a profile from GitHub.&lt;/p&gt;
&lt;p&gt;You can change your own entry or remove yourself at any time with another pull request. If a partnership ends, we remove the entry and say so in the pull request that does it. The &lt;a href=&quot;https://github.com/Cratis/Cast/blob/main/Registry/README.md&quot;&gt;registry README&lt;/a&gt; has the exact policy.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;whats-next&quot;&gt;What’s next&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The roadmap is public. &lt;a href=&quot;https://github.com/Cratis/Cast/issues/3&quot;&gt;Cratis/Cast#3&lt;/a&gt; grows the Cast into a network: case studies modeled as events, with the client’s approval, and skills earned from evidence such as merged pull requests instead of self-declared tags. &lt;a href=&quot;https://github.com/Cratis/Cast/issues/4&quot;&gt;#4&lt;/a&gt; runs the Cast on Cratis itself: the directory on Chronicle and Arc, modeled in Screenplay, with an MCP server for agents and &lt;code dir=&quot;auto&quot;&gt;cratis cast&lt;/code&gt; commands in the CLI. &lt;a href=&quot;https://github.com/Cratis/Cast/issues/5&quot;&gt;#5&lt;/a&gt; collects the ideas further out.&lt;/p&gt;
&lt;p&gt;If you build with Cratis, put your career on the stream. If you’ve shipped Cratis work with a client and want to be a Partner, open the pull request and tell us about it.&lt;/p&gt;</content:encoded><category>cast</category><category>community</category><category>event-sourcing</category></item><item><title>Not every rule needs a guarded read · Decisions that hold, Part 7</title><link>https://blog.cratis.io/not-every-rule-needs-a-guarded-read/</link><guid isPermaLink="true">https://blog.cratis.io/not-every-rule-needs-a-guarded-read/</guid><description>Read protection is the answer for state on a key you read. It is the wrong answer for a unique email, a document two people edit, or a rule you would rather repair later. Pick by the shape of the rule, and know which choices fail silently.</description><pubDate>Thu, 05 Nov 2026 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://blog.cratis.io/the-bug-you-never-see/&quot;&gt;Decisions that hold&lt;/a&gt; · Part 07 of 11&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The last five parts made one tool dependable. A command takes a read model, read protection is On, the read is folded fresh, and if an event the model folds arrives for that key before the commit, nothing is written. That is the right tool when the rule is about state on a key the command reads: the copies of one book, the loans of one member, one account’s withdrawals in one month.&lt;/p&gt;
&lt;p&gt;It is the wrong tool for a lot of other rules. A guarded read can’t make an email unique, because two members registering the same address are two different keys. It doesn’t know which revision of a document the user was looking at when they pressed save. And it costs a fold of the key’s history on every command, which a rule you would rather repair afterwards doesn’t need to pay. This part goes through the alternatives: what each one guards, when it is too much, and the mistakes that make a rule stop holding without any error.&lt;/p&gt;
&lt;p&gt;The examples assume read protection is On, as in new Cratis applications (see &lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;Part 2&lt;/a&gt;). Read protection, aggregates and the commands are part of Arc for .NET. Constraints, concurrency scopes and reactors are Chronicle, and those examples come in every Chronicle client that has them.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;start-from-the-rule-not-the-tool&quot;&gt;Start from the rule, not the tool&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/&quot;&gt;guide to choosing how a rule holds&lt;/a&gt; has a flowchart. It reads well as a list of questions, asked in order, where the first yes picks the mechanism:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/pick-by-rule-shape.BsbjML27_1LhrbH.webp&quot; alt=&quot;Seven numbered questions on the left, each with an arrow to a mechanism on the right. One: a value or event once? Constraint. Two: no stored state needed? Stateless validator. Three: fine to repair later? Reactor repair. Four: client sent a revision? Explicit scope. Five: one entity, many rules? Aggregate root. Six: one routed stream? Stream model or decision. Seven: otherwise, a guarded read under On. A line below reads: ask in order, the first yes picks the tool.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2400&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Ask in order. A guarded read is what is left when none of the other shapes fits.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The order matters. A constraint comes first because it needs no read at all: the kernel checks it inside every append, whoever writes. A rule that needs no stored state (“the title is not empty”) needs no guard either. Repair comes before every guard because when a short violation is acceptable, any guard is cost without benefit. The rest are guards of different shapes, and a guarded read is the general one at the bottom.&lt;/p&gt;
&lt;p&gt;Each section below ends with two things: what the mechanism must never be relied on for, and when it is too much. “Never rely on” means the mechanism can fail silently: the command succeeds and the rule is broken.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;a-unique-value-a-constraint&quot;&gt;A unique value: a constraint&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;A unique email is the classic check-then-act rule. A validator asks “is this email taken?”, the answer is no, and the command appends. Two requests with the same email both get “no”. Turning read protection On doesn’t change that. A guard watches the history of the key the command read, and the key here is the new member. A registration command has no member id yet, so each call starts a new member, and no read of one new member can see another.&lt;/p&gt;
&lt;p&gt;The rule belongs in the kernel, as a constraint on the event:&lt;/p&gt;
&lt;starlight-tabs data-sync-key=&quot;language&quot;&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-0&quot; id=&quot;tab-0-0&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-1&quot; id=&quot;tab-0-1&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Kotlin&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-2&quot; id=&quot;tab-0-2&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-3&quot; id=&quot;tab-0-3&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Elixir&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-4&quot; id=&quot;tab-0-4&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-0&quot; aria-labelledby=&quot;tab-0-0&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Constraints&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MemberRegistered&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;property&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Unique&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;A member with this email address is already registered.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Email&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Name&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-1&quot; aria-labelledby=&quot;tab-0-1&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// Requires io.cratis:chronicle 6.5.0 or later.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.constraints.Unique&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.events.EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MemberRegistered&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;@Unique&lt;/span&gt;&lt;span&gt;(message &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;A member with this email address is already registered.&quot;&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; email: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; name: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-2&quot; aria-labelledby=&quot;tab-0-2&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// Requires io.cratis:chronicle 6.5.0 or later.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;constraints&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Unique&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MemberRegistered&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Unique&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;A member with this email address is already registered.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; email&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-3&quot; aria-labelledby=&quot;tab-0-3&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;MemberRegistered&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;member-registered&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;email&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;unique&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;email&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;A member with this email address is already registered.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-4&quot; aria-labelledby=&quot;tab-0-4&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;unique&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/chronicle&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;member-registered&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MemberRegistered&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;unique&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;undefined&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;A member with this email address is already registered.&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;email&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;starlight-tabs-restore&gt;&lt;/starlight-tabs-restore&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;The client registers the constraint when it connects, and the kernel keeps an index of the values. Every append of &lt;code dir=&quot;auto&quot;&gt;MemberRegistered&lt;/code&gt; is checked against that index inside the append, so of two registrations with the same email, one is written and the other is rejected, whatever the timing and whoever sends them. A value belongs to an event source: the same member may append its own email again, and a new email replaces its previous claim and frees the old one.&lt;/p&gt;
&lt;p&gt;“Once per entity” is the same mechanism on the event type instead of a property. One library card per member:&lt;/p&gt;
&lt;starlight-tabs data-sync-key=&quot;language&quot;&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-1-0&quot; id=&quot;tab-1-0&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-1-1&quot; id=&quot;tab-1-1&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Kotlin&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-1-2&quot; id=&quot;tab-1-2&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-1-3&quot; id=&quot;tab-1-3&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Elixir&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-1-4&quot; id=&quot;tab-1-4&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-1-0&quot; aria-labelledby=&quot;tab-1-0&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Constraints&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Unique&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;OneLibraryCard&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;This member already has a library card.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LibraryCardIssued&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; CardNumber&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; HolderName&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-1-1&quot; aria-labelledby=&quot;tab-1-1&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// Requires io.cratis:chronicle 6.5.0 or later.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.constraints.Unique&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.events.EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@Unique&lt;/span&gt;&lt;span&gt;(id &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;OneLibraryCard&quot;&lt;/span&gt;&lt;span&gt;, message &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;This member already has a library card.&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LibraryCardIssued&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; cardNumber: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; holderName: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-1-2&quot; aria-labelledby=&quot;tab-1-2&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// Requires io.cratis:chronicle 6.5.0 or later.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;constraints&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Unique&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Unique&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;OneLibraryCard&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;This member already has a library card.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LibraryCardIssued&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; cardNumber&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; holderName&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-1-3&quot; aria-labelledby=&quot;tab-1-3&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;LibraryCardIssued&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;library-card-issued&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;card_number&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;holder_name&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;# Elixir supports a custom constraint name, but not a custom violation message.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;unique_event_type&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;OneLibraryCard&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-1-4&quot; aria-labelledby=&quot;tab-1-4&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;unique&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/chronicle&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;library-card-issued&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;unique&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;OneLibraryCard&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;This member already has a library card.&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LibraryCardIssued&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;cardNumber&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;holderName&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;starlight-tabs-restore&gt;&lt;/starlight-tabs-restore&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;An Arc command that returns either event needs nothing else. When the kernel rejects the append, Arc turns the violation into a validation result with the reason &lt;code dir=&quot;auto&quot;&gt;constraintViolation&lt;/code&gt; and your message:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;reason:  constraintViolation&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;message: A member with this email address is already registered.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A constraint has its own limits, and they are different from a guard’s. It is checked per event sequence and per namespace, so tenants in different namespaces can claim the same value. If the index update fails after an append is already durable, Chronicle logs it, and a later duplicate can pass until the index is rebuilt. A value that may change, or be given up, is released with a removal event marked &lt;code dir=&quot;auto&quot;&gt;[RemoveConstraint]&lt;/code&gt;. And it is a fixed rule about values: it can’t count, so “at most three loans” is not a constraint. &lt;a href=&quot;https://www.cratis.io/chronicle/constraints/&quot;&gt;Chronicle’s constraints documentation&lt;/a&gt; covers removal, grouping and scoping, and Einar’s post on &lt;a href=&quot;https://blog.cratis.io/invariants-at-write-time-with-chronicle-constraints/&quot;&gt;how Chronicle constraints work&lt;/a&gt; explains why the check lives in the kernel.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Never rely on&lt;/strong&gt; a validator that asks whether the value exists. &lt;strong&gt;Too much:&lt;/strong&gt; read protection added only to make a value unique. It costs a fold and still doesn’t do it.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;rich-behaviour-an-aggregate&quot;&gt;Rich behaviour: an aggregate&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;When one entity has many rules and state transitions, the rules can be easier to write as methods on the entity than as one validator per rule. A copy of a book that is lent to one member at a time, with more rules to follow:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Aggregates&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Concepts&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ConceptAs&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopyId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopyLent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Member&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopyReturned&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;AggregateRoot&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;bool&lt;/span&gt;&lt;span&gt;&lt;span&gt; _lent&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Lend&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; member&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;_lent&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;Failed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;The copy is already lent.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Apply&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopyLent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;member&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OnCopyLent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;CopyLent&lt;/span&gt;&lt;span&gt;&lt;span&gt; @event&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_lent&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OnCopyReturned&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;CopyReturned&lt;/span&gt;&lt;span&gt;&lt;span&gt; @event&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_lent&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LendCopy&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;CopyId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Copy&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Member&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;AggregateRootCommitResult&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Copy&lt;/span&gt;&lt;span&gt;&lt;span&gt; copy&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;copy&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Lend&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Member&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;copy&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commit&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;An aggregate carries its own guard. Arc rehydrates &lt;code dir=&quot;auto&quot;&gt;Copy&lt;/code&gt; from the copy’s events and notes the position of the log’s tail at that moment. The commit is guarded from that position, for the event types the aggregate handles:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;guard copy-1: types=[CopyLent, CopyReturned], after &amp;#x3C;tail when the aggregate was rehydrated&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;That is notation, not output. If another &lt;code dir=&quot;auto&quot;&gt;CopyLent&lt;/code&gt; lands on the copy between the rehydration and the commit, nothing is written. A new aggregate expects an empty history, so two commands that both create it can’t both succeed.&lt;/p&gt;
&lt;p&gt;Return the result of &lt;code dir=&quot;auto&quot;&gt;Commit()&lt;/code&gt;. &lt;code dir=&quot;auto&quot;&gt;Failed(...)&lt;/code&gt; only records the failure; &lt;code dir=&quot;auto&quot;&gt;Commit()&lt;/code&gt; turns it into a result. A handler that awaits &lt;code dir=&quot;auto&quot;&gt;Commit()&lt;/code&gt; and throws the result away reports success for a copy that was already lent, and nothing reports that mistake.&lt;/p&gt;
&lt;p&gt;Under On, an aggregate and a read model of the same event source in one command are refused with &lt;code dir=&quot;auto&quot;&gt;ReadAndAggregateOnSameSource&lt;/code&gt;, a &lt;code dir=&quot;auto&quot;&gt;500&lt;/code&gt;, and &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/code-analysis/arcchr0033/&quot;&gt;ARCCHR0033&lt;/a&gt; warns about it at build time. Decide from the aggregate’s own state instead. A read model of a different source, the member for example, is fine; each gets its own guard.&lt;/p&gt;
&lt;p&gt;The aggregate’s guard covers its own event source only. Two aggregates for two keys each guard their own, which is not a rule across both; that takes two read models, as in &lt;a href=&quot;https://blog.cratis.io/one-rule-two-entities/&quot;&gt;Part 3&lt;/a&gt;. An aggregate also has no snapshots, so every command reads the key’s handled events again, and a key with a long history gets slower with every event.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Never rely on&lt;/strong&gt; a &lt;code dir=&quot;auto&quot;&gt;Commit()&lt;/code&gt; whose result you don’t return. &lt;strong&gt;Too much:&lt;/strong&gt; a read model for each invariant of an entity that has a dozen.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;two-people-editing-an-explicit-scope&quot;&gt;Two people editing: an explicit scope&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Some conflicts are not about state the server reads. An editor loads a document at some revision, the user works on it for ten minutes, and presses save. The question is whether anyone changed it since the revision the user saw, and only the client knows that revision. A guarded read in the command reads the document fresh at save time, which is ten minutes too late.&lt;/p&gt;
&lt;p&gt;The command takes the revision as input and returns an explicit concurrency scope built from it:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSequences&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSequences&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Concurrency&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;DocumentId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;DocumentTitleChanged&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Title&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;RenameDocument&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;DocumentId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Document&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Title&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ulong&lt;/span&gt;&lt;span&gt;&lt;span&gt; ExpectedRevision&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventsWithConcurrencyScopes&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Document&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;DocumentTitleChanged&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Title&lt;/span&gt;&lt;span&gt;))],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Document&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyScope&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventSequenceNumber&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ExpectedRevision&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Document&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventTypes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;typeof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;DocumentTitleChanged&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;GetEventType&lt;/span&gt;&lt;span&gt;()]))]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;guard doc-1: types=[DocumentTitleChanged], after &amp;#x3C;ExpectedRevision&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The append fails if any &lt;code dir=&quot;auto&quot;&gt;DocumentTitleChanged&lt;/code&gt; for this document has a sequence number above &lt;code dir=&quot;auto&quot;&gt;ExpectedRevision&lt;/code&gt;. The caller gets a validation result with the reason &lt;code dir=&quot;auto&quot;&gt;concurrencyViolation&lt;/code&gt;. With two title changes at sequence numbers 0 and 1, and a client that last saw revision 0, the message reads:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Event source &apos;doc-1&apos; has new events since the command read it: expected events up to sequence number 0, but it has events up to sequence number 1. Read it again and resubmit.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;How the client learns the revision is up to your read model and query. Whatever you choose, the scope is only as strong as that number. The client chooses it, and a revision at or ahead of the log’s tail passes the check. For an editing conflict that is acceptable: a client that lies about its revision only overwrites a change its own user never saw. For a rule that protects someone else, such as an authorization or a limit, it is not. Resolve that revision on the server while handling the command, as Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/commands/events/#events-with-exact-concurrency-scopes&quot;&gt;notes on exact scopes&lt;/a&gt; say; otherwise the caller chooses which version of the fact the command is checked against.&lt;/p&gt;
&lt;p&gt;Two related shapes look similar and are not. &lt;code dir=&quot;auto&quot;&gt;concurrency: true&lt;/code&gt; on &lt;code dir=&quot;auto&quot;&gt;[EventSourceType]&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;[EventStreamType]&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;[EventStreamId]&lt;/code&gt; narrows the default check, but that check reads the tail after &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt;, so it can never carry the revision the user saw. And if the same command also takes a read model of the document, the scope must cover what that read watches and must not be captured after it; otherwise the command is refused with &lt;code dir=&quot;auto&quot;&gt;ExplicitScopeDoesNotCoverReads&lt;/code&gt;, which &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/code-analysis/arcchr0036/&quot;&gt;ARCCHR0036&lt;/a&gt; reports at build time.&lt;/p&gt;
&lt;p&gt;Without Arc, the scope goes on the append itself, and your code reads the result. Chronicle’s own example is the other common scope: opening an account, where the append must fail if the account already exists. Each client asks the kernel for that as an explicit expectation that no matching event exists, not as a sequence number:&lt;/p&gt;
&lt;starlight-tabs data-sync-key=&quot;language&quot;&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-2-0&quot; id=&quot;tab-2-0&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-2-1&quot; id=&quot;tab-2-1&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Kotlin&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-2-2&quot; id=&quot;tab-2-2&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-2-3&quot; id=&quot;tab-2-3&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Elixir&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-2-4&quot; id=&quot;tab-2-4&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-2-0&quot; aria-labelledby=&quot;tab-2-0&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSequences&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSequences&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Concurrency&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyFirstAppendCheckSetup&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// Application-wide: every first append into a scope the optimistic strategy resolves is checked.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConfigureChronicle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ChronicleOptions&lt;/span&gt;&lt;span&gt;&lt;span&gt; options&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;options&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ConcurrencyOptions&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;CheckFirstAppendIntoAScope&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyFirstAppendPartitionOpened&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Name&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyFirstAppendPartitionService&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IEventLog&lt;/span&gt;&lt;span&gt;&lt;span&gt; eventLog&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// Per append: ask for the same check on one behavior, without turning it on everywhere.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;bool&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;TryOpenPartition&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;&lt;span&gt; accountId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; concurrencyScope &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyScopeBuilder&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ExpectingNoMatchingEvent&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithEventSourceId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;accountId&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithEventType&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;ConcurrencyFirstAppendPartitionOpened&lt;/span&gt;&lt;span&gt;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Build&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; result &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;eventLog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;accountId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyFirstAppendPartitionOpened&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;concurrencyScope&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;concurrencyScope&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IsSuccess&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-2-1&quot; aria-labelledby=&quot;tab-2-1&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.IEventStore&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.events.EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.eventSequences.AppendOptions&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.eventSequences.concurrency.ConcurrencyScopeBuilder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyFirstAccountOpened&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; accountName: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* Opts in to the first-append check with [ConcurrencyScopeBuilder.withExpectsNoMatchingEvent].&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* The kernel rejects the append with a concurrency violation if an event already exists for&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* this event source, so two concurrent &quot;open account&quot; appends cannot both succeed.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;suspend&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;openAccountOnce&lt;/span&gt;&lt;span&gt;(store: &lt;/span&gt;&lt;span&gt;IEventStore&lt;/span&gt;&lt;span&gt;, accountId: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;, accountName: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;): &lt;/span&gt;&lt;span&gt;Boolean&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; concurrencyScope &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyScopeBuilder&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;withEventSourceId&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;withExpectsNoMatchingEvent&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; result &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; store.eventLog.&lt;/span&gt;&lt;span&gt;append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;accountId,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;ConcurrencyFirstAccountOpened&lt;/span&gt;&lt;span&gt;(accountName),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;AppendOptions&lt;/span&gt;&lt;span&gt;(concurrencyScope &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; concurrencyScope)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; result.isSuccess&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-2-2&quot; aria-labelledby=&quot;tab-2-2&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventStore&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eventSequences&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AppendOptions&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eventSequences&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AppendResult&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eventSequences&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;concurrency&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ConcurrencyScope&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eventSequences&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;concurrency&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ConcurrencyScopeBuilder&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;java&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventLogJavaBridge&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyFirstAccountOpened&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; accountName&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventsConcurrencyFirstAppendCheck&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// Opts in to the first-append check with withExpectsNoMatchingEvent(). The kernel rejects the&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// append with a concurrency violation if an event already exists for this event source, so&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// two concurrent &quot;open account&quot; appends cannot both succeed.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;boolean&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;openAccountOnce&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;EventStore&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;store&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;accountId&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;accountName&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;ConcurrencyScope&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;scope&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyScopeBuilder&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;withEventSourceId&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;withExpectsNoMatchingEvent&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;AppendResult&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventLogJavaBridge&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;store&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getEventLog&lt;/span&gt;&lt;span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;span&gt; accountId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyFirstAccountOpened&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;accountName&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AppendOptions&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; scope&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isSuccess&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-2-3&quot; aria-labelledby=&quot;tab-2-3&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ConcurrencyFirstAppendAccountOpened&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;concurrency-first-append-account-opened&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;account_name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ConcurrencyFirstAppendAccountService&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ConcurrencyScope&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ConcurrencyFirstAppendAccountOpened&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;# Per append: ask for the check on one behavior without changing the client&apos;s default.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;open_account&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;account_id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; account_name&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;scope &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;ConcurrencyScope&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;expecting_no_matching_event&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;event_source_id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;event_types&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ConcurrencyFirstAppendAccountOpened&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;account_id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;ConcurrencyFirstAppendAccountOpened&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&lt;span&gt;account_name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; account_name&lt;/span&gt;&lt;span&gt;},&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;concurrency_scope&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; scope&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Client&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;connection_string&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;chronicle://localhost:35000&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;event_store&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;my-store&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;concurrency&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;default&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;optimistic&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;check_first_append&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;]}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-2-4&quot; aria-labelledby=&quot;tab-2-4&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSequenceNumber&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IEventStore&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/chronicle&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;field&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/fundamentals&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyFirstAccountOpened&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;field&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;accountName&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;constructor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;accountName&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;accountName&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;accountName&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyFirstAppendService&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;constructor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;store&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IEventStore&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;openAccount&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;accountId&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;accountName&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Promise&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;// EventSequenceNumber.beforeFirst expects that no event matching the scope exists yet.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;// The client sends it as the kernel&apos;s ExpectsNoMatchingEvent condition.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;store&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eventLog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;accountId&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyFirstAccountOpened&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;accountName&lt;/span&gt;&lt;span&gt;&lt;span&gt;),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;concurrencyScope&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;sequenceNumber&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventSequenceNumber&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;beforeFirst&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventSourceId&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isSuccess&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;throw&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;The account already has events&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;starlight-tabs-restore&gt;&lt;/starlight-tabs-restore&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;The C# and Elixir versions narrow the expectation to the opening event type, so other events on the account don’t count; the Kotlin, Java and TypeScript versions expect no event at all for the account. TypeScript writes it as &lt;code dir=&quot;auto&quot;&gt;EventSequenceNumber.beforeFirst&lt;/code&gt;, which the client sends as the same no-matching-event condition. The C# and Elixir versions also show the application-wide switch, &lt;code dir=&quot;auto&quot;&gt;CheckFirstAppendIntoAScope&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;check_first_append: true&lt;/code&gt;. An expected sequence number is not the same thing: the kernel rejects such an append only when a matching event sits after that position in the log, so expecting 0 lets an append through for an account whose one event is at position 0. In .NET, &lt;code dir=&quot;auto&quot;&gt;Append&lt;/code&gt; returns a violation in its &lt;code dir=&quot;auto&quot;&gt;AppendResult&lt;/code&gt; instead of throwing, and the other clients report it in their result too, so code that appends directly has to check it. Chronicle’s &lt;a href=&quot;https://www.cratis.io/chronicle/events/concurrency/&quot;&gt;concurrency page&lt;/a&gt; covers narrowing by event type, stream and source type.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Never rely on&lt;/strong&gt; &lt;code dir=&quot;auto&quot;&gt;concurrency: true&lt;/code&gt; as the guard for a decision, or on a client-supplied revision for a rule that protects someone else. &lt;strong&gt;Too much:&lt;/strong&gt; a read model that folds the document to detect what a revision number already tells you.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;a-short-raw-stream-a-stream-decision&quot;&gt;A short raw stream: a stream decision&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.cratis.io/a-limit-for-one-month/&quot;&gt;Part 4&lt;/a&gt; covered rules that live in one routed stream, such as one account’s withdrawals in one month, with a per-stream read model. When the rule is only “has this fact happened in this stream?”, for example “has this month’s report been approved?”, there is no state to fold. A stream decision reads the raw events of the command’s own stream, captures the tail before reading, and returns a scope that fails the append if anything arrives in that stream after the read. The whole stream crosses the wire for each decision, so it suits short streams. Use either a per-stream model or a stream decision in a command, not both. &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/commands/stream-decisions/&quot;&gt;Stream decisions&lt;/a&gt; in the Arc docs has the API.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Never rely on&lt;/strong&gt; an injected read of the stream under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;. &lt;strong&gt;Too much:&lt;/strong&gt; a read of the whole event source when only one period matters.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;a-rare-violation-you-can-repair&quot;&gt;A rare violation you can repair&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Some rules can be broken for a while. An airline may let a flight be briefly overbooked and cancel the extra reservations afterwards. Then the command needs no guard: it appends with the default check, and a reactor appends a correcting event when it sees the violation.&lt;/p&gt;
&lt;p&gt;A reactor that returns an event has Chronicle append it, to the event source of the event it handled. The shape in each client:&lt;/p&gt;
&lt;starlight-tabs data-sync-key=&quot;language&quot;&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-3-0&quot; id=&quot;tab-3-0&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-3-1&quot; id=&quot;tab-3-1&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Kotlin&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-3-2&quot; id=&quot;tab-3-2&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-3-3&quot; id=&quot;tab-3-3&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Elixir&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-3-4&quot; id=&quot;tab-3-4&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-3-0&quot; aria-labelledby=&quot;tab-3-0&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Reactors&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopyReserved&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Isbn&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;StockCheckRequested&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Isbn&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;StockDecreased&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Quantity&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WarehouseReactor&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IReactor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;OnceOnly&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;StockDecreased&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopyReserved&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;CopyReserved&lt;/span&gt;&lt;span&gt;&lt;span&gt; @event&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventContext&lt;/span&gt;&lt;span&gt;&lt;span&gt; context&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;@event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;OnceOnly&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;StockDecreased&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;StockCheckRequested&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;StockCheckRequested&lt;/span&gt;&lt;span&gt;&lt;span&gt; @event&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventContext&lt;/span&gt;&lt;span&gt;&lt;span&gt; context&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; available &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;FetchCurrentStockAsync&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;@event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;StockDecreased&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;@event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;available&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;FetchCurrentStockAsync&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; isbn&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;FromResult&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-3-1&quot; aria-labelledby=&quot;tab-3-1&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.events.EventContext&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.events.EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.observation.Reactor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopyReserved&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; isbn: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;StockCheckRequested&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; isbn: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;StockDecreased&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; isbn: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; quantity: &lt;/span&gt;&lt;span&gt;Int&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@Reactor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WarehouseReactor&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// Return the event directly - it is appended to the event log using the EventSourceId from&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// the incoming event.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;copyReserved&lt;/span&gt;&lt;span&gt;(event: &lt;/span&gt;&lt;span&gt;CopyReserved&lt;/span&gt;&lt;span&gt;, context: &lt;/span&gt;&lt;span&gt;EventContext&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;StockDecreased&lt;/span&gt;&lt;span&gt;(event.isbn, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// A handler may suspend before returning its side-effect event.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;suspend&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;stockCheckRequested&lt;/span&gt;&lt;span&gt;(event: &lt;/span&gt;&lt;span&gt;StockCheckRequested&lt;/span&gt;&lt;span&gt;, context: &lt;/span&gt;&lt;span&gt;EventContext&lt;/span&gt;&lt;span&gt;): &lt;/span&gt;&lt;span&gt;StockDecreased&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; available &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fetchCurrentStock&lt;/span&gt;&lt;span&gt;(event.isbn)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;StockDecreased&lt;/span&gt;&lt;span&gt;(event.isbn, available)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;suspend&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fetchCurrentStock&lt;/span&gt;&lt;span&gt;(isbn: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;): &lt;/span&gt;&lt;span&gt;Int&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-3-2&quot; aria-labelledby=&quot;tab-3-2&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventContext&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;observation&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Reactor&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopyReserved&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; isbn&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;StockCheckRequested&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; isbn&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;StockDecreased&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; quantity&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Reactor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WarehouseReactor&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// Return the event directly - it is appended to the event log using the EventSourceId from&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// the incoming event.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;StockDecreased&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;copyReserved&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;CopyReserved&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventContext&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;context&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;StockDecreased&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;StockDecreased&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;stockCheckRequested&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;StockCheckRequested&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventContext&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;context&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;available&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fetchCurrentStock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;StockDecreased&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;span&gt; available&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fetchCurrentStock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-3-3&quot; aria-labelledby=&quot;tab-3-3&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;CopyReserved&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;copy-reserved&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;StockDecreased&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;stock-decreased&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Reactors&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WarehouseReactor&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Reactors&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Reactor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.{&lt;/span&gt;&lt;span&gt;CopyReserved&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;StockDecreased&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;handles&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopyReserved&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;impl&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;handle&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;/span&gt;&lt;span&gt;CopyReserved&lt;/span&gt;&lt;span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; event&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;_context&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;ok&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; %&lt;/span&gt;&lt;/span&gt;&lt;span&gt;StockDecreased&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;}}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-3-4&quot; aria-labelledby=&quot;tab-3-4&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventContext&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;onceOnly&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;reactor&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/chronicle&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;field&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/fundamentals&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopyReserved&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;field&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;constructor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;StockDecreased&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;field&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;field&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Number&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;number&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;constructor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;number&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;reactor&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WarehouseReactor&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// Returning an event from a handler appends it for you, targeting the triggering&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// event&apos;s own event source id, stream, and subject.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;onceOnly&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;copyReserved&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopyReserved&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;context&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventContext&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Promise&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;StockDecreased&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;StockDecreased&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;starlight-tabs-restore&gt;&lt;/starlight-tabs-restore&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;The repair itself, in C#:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSequences&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Reactors&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SeatReserved&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; ReservationId&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReservationCancelled&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; ReservationId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Reason&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OverbookingRepair&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IEventStore&lt;/span&gt;&lt;span&gt;&lt;span&gt; eventStore&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IReactor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; Capacity &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;OnceOnly&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;ReservationCancelled&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Reserved&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;SeatReserved&lt;/span&gt;&lt;span&gt;&lt;span&gt; @event&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventContext&lt;/span&gt;&lt;span&gt;&lt;span&gt; context&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; events &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;eventStore&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventLog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;GetFromSequenceNumber&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSequenceNumber&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;First&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;context&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Any&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Content&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReservationCancelled&lt;/span&gt;&lt;span&gt; cancelled &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;cancelled&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReservationId&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;@event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReservationId&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; upToThis &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Where&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Context&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;SequenceNumber&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;#x3C;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;context&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;SequenceNumber&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ToList&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; active &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;upToThis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Count&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Content&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SeatReserved&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;upToThis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Count&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Content&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReservationCancelled&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;active&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Capacity&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReservationCancelled&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;@event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReservationId&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;The flight was overbooked.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The reactor skips a reservation it has already cancelled, then counts the active reservations on the flight up to and including the one it is handling: reservations minus cancellations, so a seat a passenger gave up earlier doesn’t count against a later reservation. It cancels this reservation if the flight is over capacity. Returning &lt;code dir=&quot;auto&quot;&gt;null&lt;/code&gt; records nothing. &lt;code dir=&quot;auto&quot;&gt;[OnceOnly]&lt;/code&gt; keeps the repair out of replays, but it doesn’t make delivery exactly-once, which is why the reactor checks for its own earlier cancellation first. A reactor is not a command, so read protection doesn’t apply to it.&lt;/p&gt;
&lt;p&gt;What you give up is time. Between the violation and the repair the data is wrong, and anything that acted on it in between acted on wrong data. A repair can append a correcting event; it can’t take back an email that was sent or a boarding pass that was printed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Never rely on&lt;/strong&gt; the repair running before the harm. &lt;strong&gt;Too much:&lt;/strong&gt; any guard on a rule you have decided to repair.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;a-hint&quot;&gt;A hint&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Some reads are not the rule at all. “This book has too many reservations” may be a soft limit, where going a little over is fine, or a message you show before the user submits while the real rule is enforced somewhere else. Then the read doesn’t need a guard, and under On you say so on the parameter:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Queries&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;FluentValidation&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookReserved&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Reservations&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Increment&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookReserved&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Count&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReserveBook&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; Isbn&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookReserved&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReserveBookValidator&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CommandValidator&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;ReserveBook&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReserveBookValidator&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;Unprotected&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;soft limit: a few reservations over ten are acceptable&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Reservations&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; reservations&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;RuleFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;command &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Must&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;reservations&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;not&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Count&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithMessage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;This book has too many reservations.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt; makes the read a plain snapshot. It costs no fold and guards nothing: with ten reservations the validator refuses the command, but a reservation that lands between the read and the commit doesn’t stop it. The reason is the part a reviewer reads, so write down why staleness is acceptable or what holds the rule instead. Put the attribute on the parameter rather than the read-model type, unless every command that reads the type can live with a stale value. When the hint is only for the screen, a query is simpler still, and the command doesn’t read the model at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Never rely on&lt;/strong&gt; the hint as the rule. &lt;strong&gt;Too much:&lt;/strong&gt; a guarded read to display a message.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;external-data&quot;&gt;External data&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Some decisions use a value that isn’t in the event log at all: a price from a price list, a tax rate, an exchange rate. A command that sells a copy only while one is in stock, at the current price:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;FluentValidation&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;interface&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IPriceList&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;decimal&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;PriceOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;&lt;span&gt; bookId&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;QuotedPrice&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;decimal&lt;/span&gt;&lt;span&gt;&lt;span&gt; Amount&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopyStocked&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopySold&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;decimal&lt;/span&gt;&lt;span&gt;&lt;span&gt; Price&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopiesInStock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Increment&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;CopyStocked&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Decrement&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;CopySold&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Available&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SellCopy&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BookId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Book&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;QuotedPrice&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Provide&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IPriceList&lt;/span&gt;&lt;span&gt;&lt;span&gt; prices&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;prices&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PriceOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Book&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopySold&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QuotedPrice&lt;/span&gt;&lt;span&gt;&lt;span&gt; price&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;price&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Amount&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SellCopyValidator&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CommandValidator&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;SellCopy&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SellCopyValidator&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;CopiesInStock&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; stock&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;RuleFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;command &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Book&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Must&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;stock&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Available&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithMessage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;No copies are left.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;Provide()&lt;/code&gt; fetches the price from the service before &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; runs, and &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; puts the amount into &lt;code dir=&quot;auto&quot;&gt;CopySold&lt;/code&gt;. The &lt;code dir=&quot;auto&quot;&gt;CopiesInStock&lt;/code&gt; parameter is guarded as usual: if another &lt;code dir=&quot;auto&quot;&gt;CopySold&lt;/code&gt; for the book lands between the read and the commit, the command is refused with &lt;code dir=&quot;auto&quot;&gt;CopiesInStock &apos;book-1&apos; changed after SellCopy read it.&lt;/code&gt; and nothing is written. The price is not guarded. Read protection can’t see what &lt;code dir=&quot;auto&quot;&gt;IPriceList&lt;/code&gt; does, and a price that changes a millisecond after &lt;code dir=&quot;auto&quot;&gt;Provide()&lt;/code&gt; read it doesn’t stop the command. What you get instead is a record: the event carries the price the decision used, so nobody has to reconstruct it later from a service that has moved on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Never rely on&lt;/strong&gt; the external value being guarded. &lt;strong&gt;Too much:&lt;/strong&gt; guarding state you don’t decide from.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;what-fails-silently&quot;&gt;What fails silently&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Most mistakes with these mechanisms produce an error: a refused read, a &lt;code dir=&quot;auto&quot;&gt;500&lt;/code&gt; that names the problem, an analyzer warning. These eight don’t. The command succeeds, the tests pass one request at a time, and the rule is broken in production.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mistake&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Signal&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A “does it exist?” check for a unique value&lt;/td&gt;
&lt;td&gt;Both requests see “not taken” and both append&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;A constraint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A read under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A plain snapshot; &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; only reports what &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; would do&lt;/td&gt;
&lt;td&gt;ARCCHR0011 at Info, under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; only&lt;/td&gt;
&lt;td&gt;Turn read protection &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;Commit()&lt;/code&gt; awaited, its result ignored&lt;/td&gt;
&lt;td&gt;The command reports success though the aggregate failed&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Return &lt;code dir=&quot;auto&quot;&gt;Commit()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No event source id on the command&lt;/td&gt;
&lt;td&gt;A new random id on every call, so nothing ever conflicts&lt;/td&gt;
&lt;td&gt;ARCCHR0002 only when there are two candidates&lt;/td&gt;
&lt;td&gt;An &lt;code dir=&quot;auto&quot;&gt;EventSourceId&lt;/code&gt; property, or &lt;code dir=&quot;auto&quot;&gt;ICanProvideEventSourceId&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A model keyed differently from where the facts go&lt;/td&gt;
&lt;td&gt;The count stays at zero; the guard watches a stream nobody writes&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Write the facts to the key you read&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;concurrency: true&lt;/code&gt; as the guard&lt;/td&gt;
&lt;td&gt;The check reads the tail after &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt;, not before your read&lt;/td&gt;
&lt;td&gt;ARCCHR0016 only next to exact scopes&lt;/td&gt;
&lt;td&gt;A real guard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The first append into a new scope&lt;/td&gt;
&lt;td&gt;No tail to compare with; by default two creations both succeed&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;CheckFirstAppendIntoAScope&lt;/code&gt;, or &lt;code dir=&quot;auto&quot;&gt;ExpectingNoMatchingEvent()&lt;/code&gt; on the scope&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A writer that decides without a guard&lt;/td&gt;
&lt;td&gt;Its decision is unprotected; yours catches its event only inside your own window&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Guard every writer that decides on the rule, or use a constraint&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The last row is the easiest to miss. A guard detects any matching event appended through the kernel, whoever wrote it, but it protects only the decision that carries it. An import job that appends without reading is checked by nothing. A rule holds fully only when every writer that decides on it is guarded, or when it is a constraint, which the kernel checks on every append. Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/pitfalls/&quot;&gt;pitfalls page&lt;/a&gt; has a code example for each row.&lt;/p&gt;
&lt;aside aria-label=&quot;What to do when&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;What to do when&lt;/p&gt;&lt;div&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rule shape&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;th&gt;Never rely on&lt;/th&gt;
&lt;th&gt;Too much&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A unique value (email, user name)&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;[Unique]&lt;/code&gt; on the event property&lt;/td&gt;
&lt;td&gt;A validator asking “does it exist?”&lt;/td&gt;
&lt;td&gt;Read protection only for uniqueness&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Once per entity (one library card)&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;[Unique]&lt;/code&gt; on the event type&lt;/td&gt;
&lt;td&gt;An “exists” check in a validator&lt;/td&gt;
&lt;td&gt;A read over the whole history&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State on one key (stock, loans)&lt;/td&gt;
&lt;td&gt;A read-model parameter under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, the rule in a validator&lt;/td&gt;
&lt;td&gt;The same validator under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A constraint: it can’t count&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;An editing conflict&lt;/td&gt;
&lt;td&gt;An explicit scope with the client’s revision&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;concurrency: true&lt;/code&gt; alone&lt;/td&gt;
&lt;td&gt;A read model that folds what a revision tells you&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One short stream (approvals this month)&lt;/td&gt;
&lt;td&gt;A per-stream model or a stream decision&lt;/td&gt;
&lt;td&gt;An injected read under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A whole-source read when one period matters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rich behaviour on one entity&lt;/td&gt;
&lt;td&gt;An aggregate root that returns &lt;code dir=&quot;auto&quot;&gt;Commit()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ignoring the result of &lt;code dir=&quot;auto&quot;&gt;Commit()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A read model for each invariant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A rare, repairable violation&lt;/td&gt;
&lt;td&gt;The default append and a reactor&lt;/td&gt;
&lt;td&gt;The repair running before the harm&lt;/td&gt;
&lt;td&gt;Any guard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A hint (“too many reservations”)&lt;/td&gt;
&lt;td&gt;A query, or &lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The hint as the rule&lt;/td&gt;
&lt;td&gt;A guarded read&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;External data (a price, a tax rate)&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;Provide()&lt;/code&gt; fetches it, the event records it, a read-model parameter guards your own state&lt;/td&gt;
&lt;td&gt;Assuming the external value is guarded&lt;/td&gt;
&lt;td&gt;Guarding state you don’t decide from&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;:::&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;p&gt;The &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/scenarios/&quot;&gt;scenarios&lt;/a&gt; in the Arc docs have each shape written out, including &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/scenarios/unique-and-once/&quot;&gt;unique and once&lt;/a&gt;, &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/scenarios/aggregate/&quot;&gt;the aggregate&lt;/a&gt;, &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/scenarios/editing-conflict/&quot;&gt;the editing conflict&lt;/a&gt; and &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/scenarios/no-guard/&quot;&gt;rules that need no guard&lt;/a&gt;. &lt;a href=&quot;https://blog.cratis.io/rules-that-hold-when-you-write/&quot;&gt;Script to stage, Part 5&lt;/a&gt; goes deeper into constraints, scopes and aggregates in one application. The next part leaves Arc and builds the same guard with Chronicle’s decision reads and append conditions directly.&lt;/p&gt;&lt;p&gt;&lt;em&gt;The examples need Arc 22.108.0 or later and Chronicle 19.68.0 or later.&lt;/em&gt;&lt;/p&gt;&lt;hr&gt;&lt;ul&gt;
&lt;li&gt;Previous: &lt;a href=&quot;https://blog.cratis.io/turning-read-protection-on/&quot;&gt;Part 06 — Turning read protection on in an application that already runs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;/aside&gt;</content:encoded><category>arc</category><category>chronicle</category><category>concurrency</category><category>constraints</category><category>event-sourcing</category></item><item><title>Turning read protection on in an application that already runs · Decisions that hold, Part 6</title><link>https://blog.cratis.io/turning-read-protection-on/</link><guid isPermaLink="true">https://blog.cratis.io/turning-read-protection-on/</guid><description>You can&apos;t switch a running application to &apos;refuse unguarded reads&apos; on a hunch. Measure runs every command as before and reports which reads On would guard, which it would refuse, and which appends it would reject. Here is the path from Off to On, what a real report looks like, and how to back out.</description><pubDate>Tue, 03 Nov 2026 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://blog.cratis.io/the-bug-you-never-see/&quot;&gt;Decisions that hold&lt;/a&gt; · Part 06 of 11&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;Part 2&lt;/a&gt; turned a validator’s read into a guard with one project setting, &lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;CratisReadProtection&gt;On&amp;#x3C;/CratisReadProtection&gt;&lt;/code&gt;. New applications from the Cratis templates have that setting already. An application that already runs is a different matter. It has commands that read through &lt;code dir=&quot;auto&quot;&gt;IReadModels&lt;/code&gt;, read models with joins, and services that append to the event log as a side effect, and under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; each of those fails the command instead of running unguarded. &lt;a href=&quot;https://blog.cratis.io/when-arc-says-no/&quot;&gt;Part 5&lt;/a&gt; went through those refusals one by one. This part is about finding them before your users do.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;why-on-is-not-a-flag-you-flip&quot;&gt;Why On is not a flag you flip&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Read protection is &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; by default today. The next major version of Arc makes &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; the default (&lt;a href=&quot;https://github.com/Cratis/Arc/issues/3255&quot;&gt;Cratis/Arc#3255&lt;/a&gt;), so an explicit &lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;CratisReadProtection&gt;&lt;/code&gt; setting also keeps the mode from changing under you when you upgrade. There are three reasons not to jump straight to &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; in existing code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A protected command fails closed. It refuses a read it can’t guard, an immediate append and a read outside a parameter. Commands that work today would start returning &lt;code dir=&quot;auto&quot;&gt;500&lt;/code&gt;s.&lt;/li&gt;
&lt;li&gt;Moving a read from &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; into a parameter or a validator changes where a rule lives and what it decides from. That’s a code change per command, not a setting.&lt;/li&gt;
&lt;li&gt;A guarded read is a fresh fold of the key’s history, and costs more than a plain one. A team should choose that where a rule needs it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So Arc has a third mode between the two.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-path&quot;&gt;The path&lt;/h2&gt;&lt;/div&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;What you do&lt;/th&gt;
&lt;th&gt;What callers see&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Update the packages&lt;/td&gt;
&lt;td&gt;Nothing changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set the mode, run the application and its tests&lt;/td&gt;
&lt;td&gt;Nothing changes. Arc records what &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; would do&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read the report. Fix each refused read and immediate append, or mark a read advisory&lt;/td&gt;
&lt;td&gt;The fixes are ordinary code changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, one project at a time&lt;/td&gt;
&lt;td&gt;Switch the project and run its tests&lt;/td&gt;
&lt;td&gt;Reads are guarded, reads Arc can’t guard fail the command, and validation errors block whatever severity the caller allows&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; is set the same way as &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, in the project that contains the commands or in a &lt;code dir=&quot;auto&quot;&gt;Directory.Build.props&lt;/code&gt; that covers several:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PropertyGroup&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;CratisReadProtection&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;Measure&lt;/span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;CratisReadProtection&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;PropertyGroup&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Modes mix. A command can stay where it is while its project moves: &lt;code dir=&quot;auto&quot;&gt;[ReadProtection(ReadProtectionMode.Off)]&lt;/code&gt; (namespace &lt;code dir=&quot;auto&quot;&gt;Cratis.Arc.Commands&lt;/code&gt;) keeps one command &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; in a &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; project, and &lt;code dir=&quot;auto&quot;&gt;[ReadProtection(ReadProtectionMode.On)]&lt;/code&gt; turns one command on ahead of the rest. A command-level &lt;code dir=&quot;auto&quot;&gt;[Unprotected]&lt;/code&gt; means &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; for that command.&lt;/p&gt;
&lt;p&gt;Read protection is part of Arc for .NET.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/off-measure-on.Cf3oAamH_Z1RPKlt.webp&quot; alt=&quot;A diagram titled Off, Measure, On, with three cards joined by arrows. Off: plain reads, no change for callers, reads are snapshots. Measure: measured reads, no change for callers, Arc reports what On would do. On: guarded reads, lost races get a 400 and unguardable reads fail. A band below reads The run-time cap only ever lowers the mode.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1600&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Callers see a difference only under On.&lt;/em&gt;&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;what-measure-does-and-what-it-costs&quot;&gt;What Measure does and what it costs&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Under &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;, reads, key lookups, concurrency scopes, results and status codes stay as they are under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;. A read model in a validator is still a plain read, and it still guards nothing. What Arc adds is a record of what &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; would have done with each command. A failure inside that measurement never fails the command.&lt;/p&gt;
&lt;p&gt;It does three things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On the request path, it classifies each parameter Arc resolves for the command: a read model &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; would guard, a read &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; would refuse, an advisory read, or a dependency Arc can’t see into. This is local reflection and costs nothing beyond that.&lt;/li&gt;
&lt;li&gt;At the start of each command, it reads the event log’s tail once. This is the one awaited call Measure adds, and it has a timeout of 250 ms by default.&lt;/li&gt;
&lt;li&gt;After the command, on a sample of commands (10 percent by default), a background scan looks for events written by someone else between that tail and the scan that match what the command read. These are the commands where &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; might have returned a &lt;code dir=&quot;auto&quot;&gt;400&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The sample rate, the tail timeout, the scan timeout and the most events one scan looks at are runtime settings (&lt;code dir=&quot;auto&quot;&gt;MeasureSampleRate&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;MeasureTailTimeout&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;MeasureScanTimeout&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;MeasureScanLimit&lt;/code&gt;) in the &lt;code dir=&quot;auto&quot;&gt;ReadProtection&lt;/code&gt; configuration section. No benchmark of Measure is published. The cost has the shape above: one extra awaited call per command and background reads on a sample.&lt;/p&gt;
&lt;p&gt;It’s best effort. A command whose tail read timed out, or whose scan was dropped, is reported as &lt;code dir=&quot;auto&quot;&gt;measurement_unavailable&lt;/code&gt; and counts as no evidence either way. The report is a set of hypotheses about &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;. It isn’t protection, and an application in &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; is exactly as unguarded as one in &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;what-the-report-looks-like&quot;&gt;What the report looks like&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Take an illustrative library application with four commands. &lt;code dir=&quot;auto&quot;&gt;BorrowBook&lt;/code&gt; is Part 2’s command: a validator that takes &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt;. The other three are written the way older code often is. &lt;code dir=&quot;auto&quot;&gt;PlaceHold&lt;/code&gt; reads &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; through &lt;code dir=&quot;auto&quot;&gt;IReadModels&lt;/code&gt; in &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt;. &lt;code dir=&quot;auto&quot;&gt;ReturnBook&lt;/code&gt; calls a service that appends &lt;code dir=&quot;auto&quot;&gt;BookReturned&lt;/code&gt; through &lt;code dir=&quot;auto&quot;&gt;IEventLog&lt;/code&gt;. &lt;code dir=&quot;auto&quot;&gt;SendPickupNotice&lt;/code&gt; copies a shelf name from a read model that joins the shelf’s events. The code for each is in the next section.&lt;/p&gt;
&lt;p&gt;Measure reports through three channels:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Channel&lt;/th&gt;
&lt;th&gt;What you get&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Metric&lt;/td&gt;
&lt;td&gt;The counter &lt;code dir=&quot;auto&quot;&gt;cratis.arc.read_protection.events&lt;/code&gt; on the meter &lt;code dir=&quot;auto&quot;&gt;Cratis.Arc.ReadProtection&lt;/code&gt;, tagged &lt;code dir=&quot;auto&quot;&gt;command&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;category&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;model&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;reason&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trace&lt;/td&gt;
&lt;td&gt;A span event &lt;code dir=&quot;auto&quot;&gt;read-protection.plan&lt;/code&gt; on the current activity, with the same tags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Log&lt;/td&gt;
&lt;td&gt;A Warning once per command and category for &lt;code dir=&quot;auto&quot;&gt;refused_read&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;immediate_append&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;scope_refusal&lt;/code&gt;, and a periodic Information summary&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Start with the counter, grouped by &lt;code dir=&quot;auto&quot;&gt;category&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;command&lt;/code&gt;. Run each of the four commands once under &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;, here in an Arc &lt;code dir=&quot;auto&quot;&gt;CommandScenario&lt;/code&gt; with a &lt;code dir=&quot;auto&quot;&gt;MeterListener&lt;/code&gt; on the meter, and every one succeeds, as it would under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;. The counter receives these observations:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code dir=&quot;auto&quot;&gt;command&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code dir=&quot;auto&quot;&gt;category&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code dir=&quot;auto&quot;&gt;model&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code dir=&quot;auto&quot;&gt;reason&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;BorrowBook&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;protected_read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;Would be protected&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;PlaceHold&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;refused_read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;Cratis.Chronicle.ReadModels.IReadModels&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;IReadModels&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;ReturnBook&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;immediate_append&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;BookReturned&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;Would be refused while reads are protected&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;SendPickupNotice&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;refused_read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;BookCard&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;Join&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The category that matters most is missing: &lt;code dir=&quot;auto&quot;&gt;matching_events_since_start&lt;/code&gt;, even though the &lt;code dir=&quot;auto&quot;&gt;BorrowBook&lt;/code&gt; run had another member’s &lt;code dir=&quot;auto&quot;&gt;BookBorrowed&lt;/code&gt; appended between its read and its commit. That category comes from the background scan, and a &lt;code dir=&quot;auto&quot;&gt;CommandScenario&lt;/code&gt; can’t run the scan. It has no host to start the scan queue, and its in-process event log can’t serve the scan’s reads, so a sampled command there reports &lt;code dir=&quot;auto&quot;&gt;measurement_unavailable&lt;/code&gt; instead. Races show up in the scan of a running application with real traffic, which is where Measure belongs, not only in your test suite.&lt;/p&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;ReturnBook&lt;/code&gt; also reported &lt;code dir=&quot;auto&quot;&gt;unknown_dependency&lt;/code&gt; for &lt;code dir=&quot;auto&quot;&gt;ILoanLedger&lt;/code&gt;, the service it calls. Every command in that run reported &lt;code dir=&quot;auto&quot;&gt;unknown_dependency&lt;/code&gt; for services resolved by the framework rather than by the command, too: &lt;code dir=&quot;auto&quot;&gt;Orleans.IGrainFactory&lt;/code&gt; from the in-process test kernel, &lt;code dir=&quot;auto&quot;&gt;Cratis.Chronicle.Sequences.RequestCausation&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;Cratis.Arc.Authorization.ICurrentPrincipalAccessor&lt;/code&gt;. They’re left out of the table. Which of these appear depends on the host, so when you group the counter, look at the dependencies that are yours. The &lt;code dir=&quot;auto&quot;&gt;command&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;model&lt;/code&gt; tags are full type names; the example’s types are in the global namespace, so they’re short here.&lt;/p&gt;
&lt;p&gt;The log said the same thing for the three that need work, once each:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Read-protection hypothesis for PlaceHold: category=refused_read, model=Cratis.Chronicle.ReadModels.IReadModels, reason=IReadModels; this may need attention before turning On&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Read-protection hypothesis for ReturnBook: category=immediate_append, model=BookReturned, reason=Would be refused while reads are protected; this may need attention before turning On&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Read-protection hypothesis for SendPickupNotice: category=refused_read, model=BookCard, reason=Join; this may need attention before turning On&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;These are the categories you’ll meet most:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code dir=&quot;auto&quot;&gt;category&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;What it means&lt;/th&gt;
&lt;th&gt;What to do&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;protected_read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; would guard this read&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;refused_read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; would refuse this read. &lt;code dir=&quot;auto&quot;&gt;reason&lt;/code&gt; names the cause or the API&lt;/td&gt;
&lt;td&gt;Fix it, or mark it advisory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;advisory_read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The read is marked &lt;code dir=&quot;auto&quot;&gt;[Unprotected]&lt;/code&gt;. &lt;code dir=&quot;auto&quot;&gt;reason&lt;/code&gt; is your text&lt;/td&gt;
&lt;td&gt;Check the reason still holds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;immediate_append&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The command appended through &lt;code dir=&quot;auto&quot;&gt;IEventLog&lt;/code&gt; at once, and &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; would refuse it&lt;/td&gt;
&lt;td&gt;Return the event from &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;unknown_dependency&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A service Arc can’t see into&lt;/td&gt;
&lt;td&gt;Check what the service reads. A Chronicle read inside it is still refused under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;redirect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; would look the model up by a different key than today&lt;/td&gt;
&lt;td&gt;Say which key you mean with &lt;code dir=&quot;auto&quot;&gt;[LookUpBy]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;matching_events_since_start&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Someone else wrote an event matching the read while the command ran. &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; might have returned &lt;code dir=&quot;auto&quot;&gt;400&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A real race. These commands gain the most from &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;scope_refusal&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; would refuse the command’s explicit concurrency scope as narrower than the read, captured after it, or incomplete&lt;/td&gt;
&lt;td&gt;Widen the scope or remove it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;measurement_unavailable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A measurement couldn’t be taken. &lt;code dir=&quot;auto&quot;&gt;reason&lt;/code&gt; says why&lt;/td&gt;
&lt;td&gt;Raise the timeouts, or ignore it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;mode_lowered&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The run-time cap lowered the declared mode&lt;/td&gt;
&lt;td&gt;See the last section&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The full list, including &lt;code dir=&quot;auto&quot;&gt;displacement&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;coarsened&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;self_write&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;conflict_today&lt;/code&gt;, is on Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/adopting/#reading-the-report&quot;&gt;Adopting read protection&lt;/a&gt; page.&lt;/p&gt;
&lt;p&gt;A quiet report isn’t a clean bill of health. Measure doesn’t currently report everything &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; would do differently: it can’t tell from its observations which concurrency scopes were explicit and which were derived, and it doesn’t see a nested command reading an event its outer command has staged but not committed. The absence of a category means only that Measure didn’t observe it. The background scan runs on a sample, so a race that happened on an unsampled command isn’t in the report either.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;fixing-what-it-finds&quot;&gt;Fixing what it finds&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The examples use &lt;code dir=&quot;auto&quot;&gt;Isbn&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;MemberId&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; and the book events from Part 2, and one new event:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;HoldPlaced&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Member&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;a-read-through-ireadmodels&quot;&gt;A read through IReadModels&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;PlaceHold&lt;/code&gt; lets a member queue for a book when no copy is on the shelf. The rule lives in &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt;, and the read goes through &lt;code dir=&quot;auto&quot;&gt;IReadModels&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Validation&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Monads&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PlaceHold&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; Isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Member&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;HoldPlaced&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ValidationResult&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IReadModels&lt;/span&gt;&lt;span&gt;&lt;span&gt; readModels&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; stock &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;readModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;GetInstanceById&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookStock&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;stock&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Available&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ValidationResult&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;A copy is on the shelf. Borrow it instead.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;HoldPlaced&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Member&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, Arc refuses the &lt;code dir=&quot;auto&quot;&gt;GetInstanceById&lt;/code&gt; call with a &lt;code dir=&quot;auto&quot;&gt;500&lt;/code&gt;, because a read through &lt;code dir=&quot;auto&quot;&gt;IReadModels&lt;/code&gt; has no position and can’t guard the append. The fix is the shape from Part 2. The read becomes a constructor parameter of a validator, and the rule moves with it:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;FluentValidation&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PlaceHold&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; Isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Member&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;HoldPlaced&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Member&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PlaceHoldValidator&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CommandValidator&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PlaceHold&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PlaceHoldValidator&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BookStock&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; stock&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;RuleFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;command &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Must&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;stock&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;not&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Available&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithMessage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;A copy is on the shelf. Borrow it instead.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, that &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; is folded fresh and guards the append. A copy returned between the read and the commit makes the command fail with &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt; instead of placing a hold on a book that is on the shelf.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;an-append-that-happens-at-once&quot;&gt;An append that happens at once&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;ReturnBook&lt;/code&gt; doesn’t append through its return value. It calls a service, and the service appends:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSequences&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;interface&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ILoanLedger&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;RecordReturn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; member&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LoanLedger&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IEventLog&lt;/span&gt;&lt;span&gt;&lt;span&gt; eventLog&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ILoanLedger&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;RecordReturn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; member&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventLog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;member&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReturnBook&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; Isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Member&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ILoanLedger&lt;/span&gt;&lt;span&gt;&lt;span&gt; ledger&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ledger&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;RecordReturn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Member&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;IEventLog.Append&lt;/code&gt; writes at once, before the command commits. If the command’s guard then conflicts, nothing rolls that event back, so under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; Arc refuses it. The build doesn’t see this one. Arc’s analyzers warn when &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; takes &lt;code dir=&quot;auto&quot;&gt;IEventLog&lt;/code&gt; itself (ARCCHR0007), but here the append is behind an interface, and it compiled without a diagnostic. Measure saw it at run time, as &lt;code dir=&quot;auto&quot;&gt;immediate_append&lt;/code&gt; with the event type, next to &lt;code dir=&quot;auto&quot;&gt;unknown_dependency&lt;/code&gt; for &lt;code dir=&quot;auto&quot;&gt;ILoanLedger&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The fix is to return the event, so it’s committed with the command:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReturnBook&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; Isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Member&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Member&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;When the append has to stay in a service, &lt;code dir=&quot;auto&quot;&gt;IEventLog.Transactional.Append&lt;/code&gt; adds the event to the command’s unit of work instead of writing it at once, and &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; accepts that.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;a-read-model-with-a-join&quot;&gt;A read model with a join&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;SendPickupNotice&lt;/code&gt; tells a member where to collect a book, and takes the shelf’s name from a read model that joins the shelf’s events:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Queries&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Concepts&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ShelfId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ConceptAs&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookShelved&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ShelfId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Shelf&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ShelfNamed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Name&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PickupNoticeSent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Member&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Shelf&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookCard&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookShelved&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ShelfId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Shelf&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Join&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;ShelfNamed&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;on&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nameof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Shelf&lt;/span&gt;&lt;span&gt;&lt;span&gt;),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventPropertyName&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nameof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ShelfNamed&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Name&lt;/span&gt;&lt;span&gt;&lt;span&gt;))]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; ShelfName&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SendPickupNotice&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; Isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Member&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PickupNoticeSent&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BookCard&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; card&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Member&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;card&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShelfName&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;??&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Front desk&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A joined model folds events from more than one key, so a guard on the book’s key can’t cover it, and &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; refuses the read. This one the build flags already in &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;: ARCCHR0024 warns that &lt;code dir=&quot;auto&quot;&gt;BookCard&lt;/code&gt; has joins or children, “so protection is not proven”.&lt;/p&gt;
&lt;p&gt;There are two honest answers. If a decision depends on the joined data, read the parts as separate models, each keyed by its own entity, and look each up by the command property that holds its key with &lt;code dir=&quot;auto&quot;&gt;[LookUpBy]&lt;/code&gt; (&lt;a href=&quot;https://blog.cratis.io/one-rule-two-entities/&quot;&gt;Part 3&lt;/a&gt; does that for a book and a member). Here the shelf name is only copied into the notice, and a stale name is acceptable, so the read can say so:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SendPickupNotice&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; Isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Member&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PickupNoticeSent&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;Unprotected&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;copied as of read; may be stale&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;BookCard&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; card&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Member&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;card&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShelfName&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;??&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Front desk&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;An &lt;code dir=&quot;auto&quot;&gt;[Unprotected]&lt;/code&gt; read is a stored read that guards nothing, on purpose. Measure then reports it as &lt;code dir=&quot;auto&quot;&gt;advisory_read&lt;/code&gt; with your reason, so the reasons stay visible in the same report. Use it for context, never to silence a refusal you don’t understand.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;the-other-categories&quot;&gt;The other categories&lt;/h3&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;redirect&lt;/code&gt;: under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;, Arc looks up a read-model parameter by the command’s event source id. Under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, it uses the one command property whose type is the model’s &lt;code dir=&quot;auto&quot;&gt;Id&lt;/code&gt; type, when there is one. A &lt;code dir=&quot;auto&quot;&gt;redirect&lt;/code&gt; means those two disagree for this command, so &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; would read a different instance. Put &lt;code dir=&quot;auto&quot;&gt;[LookUpBy(nameof(Property))]&lt;/code&gt; (namespace &lt;code dir=&quot;auto&quot;&gt;Cratis.Arc.Commands&lt;/code&gt;) on the parameter, naming the command property that holds the key you mean. It applies in every mode, so the lookup no longer changes when the project moves to &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;refused_read&lt;/code&gt; with other reasons: a reducer with an event filter or constructor dependencies, children, a key taken from an event property, Pinned generation delivery. Part 5 has the table of reasons and fixes.&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;unknown_dependency&lt;/code&gt;: look inside the service. If it calls an HTTP API or another database, there’s nothing to fix, and that read stays outside the guard under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; too. If it reads Chronicle, through &lt;code dir=&quot;auto&quot;&gt;IReadModels&lt;/code&gt; for example, Measure records only the service, but &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; still refuses the read when the command runs. Move that read into a parameter of the command, as with &lt;code dir=&quot;auto&quot;&gt;PlaceHold&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;switching-a-project-to-on&quot;&gt;Switching a project to On&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;When a project’s report shows only &lt;code dir=&quot;auto&quot;&gt;protected_read&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;advisory_read&lt;/code&gt; with reasons you still agree with, and dependencies you know about:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set &lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;CratisReadProtection&gt;On&amp;#x3C;/CratisReadProtection&gt;&lt;/code&gt; for that project.&lt;/li&gt;
&lt;li&gt;Build, and fix ARCCHR0024 (a read model shape that can’t be protected), ARCCHR0028 (a Chronicle read that isn’t proven protected) and ARCCHR0033 (an aggregate and a read of the same source). Raise them to errors in projects you’ve moved.&lt;/li&gt;
&lt;li&gt;Run the project’s tests. Arc’s &lt;code dir=&quot;auto&quot;&gt;CommandScenario&lt;/code&gt; picks the in-process event log that supports guarded reads from the command’s mode, so the scenarios run the commands under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;. Part 9 is about testing the race itself.&lt;/li&gt;
&lt;li&gt;Exercise every command at least once. Refusals happen when a command runs, not at startup, and a command nobody ran under &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; has no report.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;From Arc 22.108.0, a command declared &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; also blocks on &lt;code dir=&quot;auto&quot;&gt;Error&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;Unknown&lt;/code&gt; validation results whatever &lt;code dir=&quot;auto&quot;&gt;X-Allowed-Severity&lt;/code&gt; the caller sends (&lt;a href=&quot;https://blog.cratis.io/when-arc-says-no/&quot;&gt;Part 5&lt;/a&gt; explains why). Measure has no category for this, so look for clients that send an allowed severity before you switch.&lt;/p&gt;
&lt;p&gt;Under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, a validator with read-model parameters has to be registered by convention, so Arc can build a fresh one per command. A validator registered by hand as scoped, singleton, a factory or an instance is refused.&lt;/p&gt;
&lt;p&gt;With the fixed commands in an &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; project, &lt;code dir=&quot;auto&quot;&gt;PlaceHold&lt;/code&gt; places a hold when no copy is on the shelf and fails with the rule’s message when one is. With a &lt;code dir=&quot;auto&quot;&gt;BookReturned&lt;/code&gt; appended between its read and its commit, it fails with &lt;code dir=&quot;auto&quot;&gt;concurrencyViolation&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt;, and nothing is written. &lt;code dir=&quot;auto&quot;&gt;ReturnBook&lt;/code&gt; commits its event with the command, and &lt;code dir=&quot;auto&quot;&gt;SendPickupNotice&lt;/code&gt; runs with its advisory read.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;backing-out-at-run-time&quot;&gt;Backing out at run time&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;If something goes wrong after a deployment with &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, operations can lower the mode without a build:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;ReadProtection&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;MaximumMode&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Measure&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code dir=&quot;auto&quot;&gt;MaximumMode&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, missing or invalid&lt;/td&gt;
&lt;td&gt;The compiled modes apply&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Commands compiled as &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; run as &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Commands compiled as &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; run as &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The cap only lowers. It never raises a mode that wasn’t compiled in, so a missing or mistyped value can’t switch anything on. At startup, Arc logs a Warning for each command it lowers, in this form (the command name here is an example):&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Read protection for Library.PlaceHold is lowered from On to Measure by ReadProtection:MaximumMode.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Measure reports &lt;code dir=&quot;auto&quot;&gt;mode_lowered&lt;/code&gt; for those commands too. The cap lowers the guard, not the severity floor: that follows the declared mode, so a command declared &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; keeps blocking on &lt;code dir=&quot;auto&quot;&gt;Error&lt;/code&gt; under any cap. Only changing the declared mode to &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; gives callers their threshold back. There, callers filter as before, so declare &lt;code dir=&quot;auto&quot;&gt;[BlockOnValidationSeverity(ValidationResultSeverity.Error)]&lt;/code&gt; on a command whose validators must not be skipped. With the cap set, the commands run unguarded, so use it to get through an incident while you fix the code, and then remove it. &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; and a lowered cap both leave an application that looks protected and isn’t. Check that production configuration has no cap you didn’t set on purpose.&lt;/p&gt;
&lt;aside aria-label=&quot;What to do when&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;What to do when&lt;/p&gt;&lt;div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;New code:&lt;/strong&gt; start with &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, as the Cratis templates do (Part 2).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An application that already runs:&lt;/strong&gt; set &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;, run it for a representative period, and group &lt;code dir=&quot;auto&quot;&gt;cratis.arc.read_protection.events&lt;/code&gt; by &lt;code dir=&quot;auto&quot;&gt;category&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;command&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code dir=&quot;auto&quot;&gt;refused_read&lt;/code&gt;:&lt;/strong&gt; fix it per its &lt;code dir=&quot;auto&quot;&gt;reason&lt;/code&gt;, or mark the read &lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt; if it’s only context.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code dir=&quot;auto&quot;&gt;immediate_append&lt;/code&gt;:&lt;/strong&gt; return the event from &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt;, or use &lt;code dir=&quot;auto&quot;&gt;IEventLog.Transactional.Append&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code dir=&quot;auto&quot;&gt;redirect&lt;/code&gt;:&lt;/strong&gt; add &lt;code dir=&quot;auto&quot;&gt;[LookUpBy(nameof(Property))]&lt;/code&gt; to the parameter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code dir=&quot;auto&quot;&gt;matching_events_since_start&lt;/code&gt;:&lt;/strong&gt; a race that already happens. Move these commands first.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A quiet report:&lt;/strong&gt; run every command, and remember the scan is sampled. Absence isn’t evidence.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An incident after switching to &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;:&lt;/strong&gt; set &lt;code dir=&quot;auto&quot;&gt;ReadProtection:MaximumMode&lt;/code&gt; to &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;, fix the code, and remove the cap.&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/adopting/&quot;&gt;Adopting read protection&lt;/a&gt; has the full category list and the refusal reasons, and &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/pitfalls/&quot;&gt;Pitfalls&lt;/a&gt; covers what still fails silently once a project is &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;. &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/#why-protection-is-opt-in&quot;&gt;Why protection is opt-in&lt;/a&gt; gives the reasons &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; is the default.&lt;/p&gt;
&lt;p&gt;The next part steps back from read protection. Not every rule needs a guarded read: uniqueness is a constraint, rich behaviour is an aggregate, and some rules are cheaper to repair than to guard.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Read protection as described here needs Arc 22.108.0 or later and Chronicle 19.68.0 or later.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;Previous: &lt;a href=&quot;https://blog.cratis.io/when-arc-says-no/&quot;&gt;Part 05 — When Arc says no&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>arc</category><category>chronicle</category><category>concurrency</category><category>event-sourcing</category></item><item><title>When Arc says no · Decisions that hold, Part 5</title><link>https://blog.cratis.io/when-arc-says-no/</link><guid isPermaLink="true">https://blog.cratis.io/when-arc-says-no/</guid><description>Read protection says no in two ways. A 400 means something the command read changed: read again and decide. A 500 means the code reads something Arc can&apos;t guard: change the code. And under Off, a caller can turn a validator&apos;s no into a yes.</description><pubDate>Fri, 30 Oct 2026 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://blog.cratis.io/the-bug-you-never-see/&quot;&gt;Decisions that hold&lt;/a&gt; · Part 05 of 11&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The previous parts were about getting a decision to hold: a guarded read of one entity, of two, and of one month. Each ended at the same place, a command that Arc refuses when the state it decided from has changed. This part is about the refusals themselves. Read protection fails closed: when it can’t guard a read exactly, it refuses the command instead of running it unguarded. That leaves the caller with two kinds of no, and they need different handling.&lt;/p&gt;
&lt;p&gt;There’s also a no that a command doesn’t give when it should. Under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;, a stale read can approve a borrow, and so can a caller who asks Arc to ignore the validator’s errors. The last section covers both, and what &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; changes.&lt;/p&gt;
&lt;p&gt;The examples assume read protection is On, as in new Cratis applications (see &lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;Part 2&lt;/a&gt;). Read protection is part of Arc for .NET; the frontend code below is Arc’s TypeScript client.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;two-kinds-of-no&quot;&gt;Two kinds of no&lt;/h2&gt;&lt;/div&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;What it means&lt;/th&gt;
&lt;th&gt;What to do&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;The read changed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;400&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;An event that the command’s read depends on arrived before it committed. Nothing was written&lt;/td&gt;
&lt;td&gt;Read again, and let the user decide again&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;The code can’t be guarded&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;500&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The command reads or appends something Arc can’t put under a guard. Nothing was written&lt;/td&gt;
&lt;td&gt;Change the code. Submitting again fails the same way&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Neither one is retried for you. Arc and Chronicle don’t re-run the command. A &lt;code dir=&quot;auto&quot;&gt;400&lt;/code&gt; means the state the decision rested on has moved, and a blind resubmit of the same decision would undo the point of the guard. A &lt;code dir=&quot;auto&quot;&gt;500&lt;/code&gt; is a configuration error, and nothing about the next request will be different.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/two-kinds-of-no.Dp74tuBx_19X7Kn.webp&quot; alt=&quot;A diagram titled Two kinds of no, in two frames. The left frame, 400: submit again, has two cards with the reason concurrencyViolation: ReadChanged, what you read changed, and ReadIncomplete, the fold could not finish. Below them a green card reads Nothing written, read again and decide. The right frame, 500: change the code, has two cards: A read-model parameter, shape cannot be guarded, and Inside the command, refused reads and appends. Below them a red card reads Nothing written, resubmitting fails again. A band reads Arc and Chronicle do not re-run the command.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2200&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The two families of refusal, and what each asks of the caller.&lt;/em&gt;&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-read-changed&quot;&gt;The read changed&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;Part 2&lt;/a&gt; showed the common one. Two members borrow the last copy, and the second commit is refused:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;BookStock &apos;isbn-1&apos; changed after BorrowBook read it. Nothing from this command was written; submit it again.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The validation result carries the reason &lt;code dir=&quot;auto&quot;&gt;concurrencyViolation&lt;/code&gt;, the detail &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt;, and a state object naming the model and the key, &lt;code dir=&quot;auto&quot;&gt;{&quot;readModel&quot;:&quot;BookStock&quot;,&quot;key&quot;:&quot;isbn-1&quot;}&lt;/code&gt;. It has no &lt;code dir=&quot;auto&quot;&gt;members&lt;/code&gt;. It isn’t about any field of the command, and nothing the user typed was wrong.&lt;/p&gt;
&lt;p&gt;The second &lt;code dir=&quot;auto&quot;&gt;400&lt;/code&gt; comes from the read, not the commit:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;BookStock &apos;isbn-1&apos; could not be read completely. Nothing was written; submit it again.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;That’s &lt;code dir=&quot;auto&quot;&gt;ReadIncomplete&lt;/code&gt;. Before each attempt at a guarded read, Chronicle notes the position of the log and of the last event of the model’s types for that key, and then folds. If the fold doesn’t reach that last event, it tries again. It makes up to three attempts in total, and if the last one still falls short, the read fails and the command stops. Events that arrive during the fold are a different case: they make Chronicle fold again too, but the last attempt returns a guarded read, and a conflict shows up at commit as &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt;. A &lt;code dir=&quot;auto&quot;&gt;ReadIncomplete&lt;/code&gt; result has the reason &lt;code dir=&quot;auto&quot;&gt;concurrencyViolation&lt;/code&gt; too, with the detail &lt;code dir=&quot;auto&quot;&gt;ReadIncomplete&lt;/code&gt; and no state. Submitting again is safe for the same reason as with &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt;: the next request reads fresh state and runs every rule again.&lt;/p&gt;
&lt;p&gt;You get one result per guarded read that changed. A command whose validator reads both &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; and a &lt;code dir=&quot;auto&quot;&gt;BookTitle&lt;/code&gt; model of the same book guards both, and a concurrent retitle produces a &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt; for each of them, &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; included, although &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; doesn’t fold titles. Reads of one event source merge into one guard that covers the event types of all of them, so an event that conflicts with the guard conflicts with every read in it. That’s one reason to keep context you don’t decide from out of the guard, as the section on advisory reads below shows.&lt;/p&gt;
&lt;p&gt;The message doesn’t name the event that caused the conflict. Chronicle doesn’t report it yet.&lt;/p&gt;
&lt;p&gt;Commands that opted in on their own with &lt;code dir=&quot;auto&quot;&gt;[ProtectedDecision]&lt;/code&gt;, outside &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, word it differently and carry no detail: &lt;code dir=&quot;auto&quot;&gt;BookStock &apos;isbn-1&apos; changed after it was read. Read it again and resubmit.&lt;/code&gt; Branch on the reason, not on the text.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;handling-it-in-the-ui&quot;&gt;Handling it in the UI&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Arc’s frontend puts the same fields on each validation result: &lt;code dir=&quot;auto&quot;&gt;reason&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;reasonDetail&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;state&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;members&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;message&lt;/code&gt;. The only reason whose message is meant for the user is &lt;code dir=&quot;auto&quot;&gt;rule&lt;/code&gt;, a rule you wrote. A &lt;code dir=&quot;auto&quot;&gt;concurrencyViolation&lt;/code&gt; message is developer text in English. A UI decides from &lt;code dir=&quot;auto&quot;&gt;reason&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ICommandResult&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/arc/commands&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ValidationResultReason&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/arc/validation&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Outcome&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;done&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;readAgain&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;rejected&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;failed&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;outcomeOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ICommandResult&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;unknown&lt;/span&gt;&lt;span&gt;&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Outcome&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isSuccess&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;done&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;reasons&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;validationResults&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;reason&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;reasons&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;includes&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ValidationResultReason&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ConcurrencyViolation&lt;/span&gt;&lt;span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;readAgain&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;reasons&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;includes&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ValidationResultReason&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Rule&lt;/span&gt;&lt;span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;rejected&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;failed&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Every &lt;code dir=&quot;auto&quot;&gt;concurrencyViolation&lt;/code&gt; asks for the same thing, whichever guard produced it: read again and decide. &lt;code dir=&quot;auto&quot;&gt;reasonDetail&lt;/code&gt; says which kind it was, &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;ReadIncomplete&lt;/code&gt;, and is a plain string with no TypeScript constant. Use it for wording or telemetry if you need to. &lt;code dir=&quot;auto&quot;&gt;reason&lt;/code&gt; is an open set. Arc’s own guidance is to treat an unfamiliar value like &lt;code dir=&quot;auto&quot;&gt;rule&lt;/code&gt;; this handler deliberately sends it to &lt;code dir=&quot;auto&quot;&gt;failed&lt;/code&gt; and shows generic copy, because it can’t know that the message was written for a user.&lt;/p&gt;
&lt;p&gt;In a React form, the same function runs from &lt;code dir=&quot;auto&quot;&gt;CommandForm&lt;/code&gt;’s &lt;code dir=&quot;auto&quot;&gt;onFailed&lt;/code&gt; callback, which receives the whole command result:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;useState&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;react&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CommandForm&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/arc.react/commands&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ValidationResultReason&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/arc/validation&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;./BorrowBook&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;outcomeOf&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;./outcome&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Props&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;member&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;onReadAgain&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowButton&lt;/span&gt;&lt;span&gt;&lt;span&gt;({&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;member&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;onReadAgain&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Props&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;notice&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;setNotice&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;useState&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;CommandForm&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;initialValues&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt;{{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;member&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;onSuccess&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt;{()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;setNotice&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;Borrowed.&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;onFailed&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                &lt;/span&gt;&lt;span&gt;switch&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;outcomeOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                    &lt;/span&gt;&lt;span&gt;case&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;readAgain&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                        &lt;/span&gt;&lt;span&gt;onReadAgain&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                        &lt;/span&gt;&lt;span&gt;setNotice&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;This book changed while you were looking. Check the stock and borrow again if you still want it.&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                        &lt;/span&gt;&lt;span&gt;break&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                    &lt;/span&gt;&lt;span&gt;case&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;rejected&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                        &lt;/span&gt;&lt;span&gt;setNotice&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;validationResults&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;filter&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;reason&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;===&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ValidationResultReason&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Rule&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;message&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                        &lt;/span&gt;&lt;span&gt;break&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                    &lt;/span&gt;&lt;span&gt;default&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                        &lt;/span&gt;&lt;span&gt;setNotice&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;The library could not lend this book right now.&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}}&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;submit&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;Borrow&lt;/span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;role&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&gt;{&lt;/span&gt;&lt;span&gt;notice&lt;/span&gt;&lt;span&gt;}&amp;#x3C;/&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;CommandForm&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;BorrowBook&lt;/code&gt; is the proxy Arc generates for the command. &lt;code dir=&quot;auto&quot;&gt;onReadAgain&lt;/code&gt; is the page’s own: it reloads whatever showed the stock, so the user decides from the new value. The rule’s message, “No copies of this book are available.”, is the user’s to see, and only &lt;code dir=&quot;auto&quot;&gt;rule&lt;/code&gt; messages are shown. Its result names the &lt;code dir=&quot;auto&quot;&gt;isbn&lt;/code&gt; member, so a form with an &lt;code dir=&quot;auto&quot;&gt;isbn&lt;/code&gt; field shows it there. A &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt; names no member, so &lt;code dir=&quot;auto&quot;&gt;CommandForm&lt;/code&gt; never attaches it to a field.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.cratis.io/validation-all-the-way-down/&quot;&gt;&lt;em&gt;Validation all the way down&lt;/em&gt;&lt;/a&gt; covers results, reasons and severities in general. The only thing read protection adds is &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;ReadIncomplete&lt;/code&gt; under a reason a UI already had to handle.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-code-cant-be-guarded&quot;&gt;The code can’t be guarded&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;A &lt;code dir=&quot;auto&quot;&gt;500&lt;/code&gt; from read protection means the command reads or appends something that Arc can’t fold fresh and put under a guard. Under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; the same code runs, unguarded. Under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; it’s refused before anything is written, and the message names the read and the fix. For a read-model parameter whose model has a shape Chronicle can’t guard, it looks like this:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;BorrowBook reads &apos;details&apos; (BookDetails) with joins or children, so read protection cannot guard it. If it is only context, mark it [Unprotected(&quot;why&quot;)]. Otherwise read the parts as separate models.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The common causes, and what to change:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Refusal&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;ReadCannotBeProtected&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A read-model parameter whose model has joins or children&lt;/td&gt;
&lt;td&gt;Read the parts as separate models&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;ReadCannotBeProtected&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A read-model parameter keyed by an event property&lt;/td&gt;
&lt;td&gt;Append a fact to the entity the model is keyed by, or use a constraint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;ReadCannotBeProtected&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A model built by a reducer with an event filter or constructor dependencies&lt;/td&gt;
&lt;td&gt;Remove the filter or the dependencies, or read an unfiltered projection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;ReadCannotBeProtected&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A projection with Pinned generation delivery, or a model of another event sequence&lt;/td&gt;
&lt;td&gt;Use Compatibility delivery; read a model of the event log&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;ReadCannotBeProtected&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;An &lt;code dir=&quot;auto&quot;&gt;IMongoCollection&amp;#x3C;T&gt;&lt;/code&gt; of a Chronicle-backed model&lt;/td&gt;
&lt;td&gt;Take the read model as a parameter instead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;AmbiguousReadModelLookup&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Several command properties have the model’s &lt;code dir=&quot;auto&quot;&gt;Id&lt;/code&gt; type&lt;/td&gt;
&lt;td&gt;Name one with &lt;code dir=&quot;auto&quot;&gt;[LookUpBy(nameof(Property))]&lt;/code&gt; on the parameter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;ReadRefusedWhileReadsAreProtected&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A read through &lt;code dir=&quot;auto&quot;&gt;IReadModels&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;IEventStore&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;IEventLog&lt;/code&gt; or an event sequence inside the command&lt;/td&gt;
&lt;td&gt;Take the read model as a parameter, use &lt;code dir=&quot;auto&quot;&gt;IDecisionReads.Get&lt;/code&gt; in &lt;code dir=&quot;auto&quot;&gt;Provide()&lt;/code&gt;, or mark the method &lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;ImmediateAppendWhileReadsAreProtected&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;IEventLog.Append&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;AppendMany&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;Revise&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;Redact&lt;/code&gt;, which write at once&lt;/td&gt;
&lt;td&gt;Return the event from &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt;, or stage it with &lt;code dir=&quot;auto&quot;&gt;IEventLog.Transactional.Append&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;ReadAndAggregateOnSameSource&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;An aggregate and a guarded read-model parameter of the same event source in one command&lt;/td&gt;
&lt;td&gt;Decide from the aggregate’s state, read another source, or mark the read &lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt; if it’s only context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;DiscoverableValidatorRefusedInProtectedDecision&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A validator registered by hand as scoped, singleton, a factory or an instance&lt;/td&gt;
&lt;td&gt;Let convention discovery register it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;An immediate append is refused for a reason that has nothing to do with reads: it’s written before the commit and stays if the commit conflicts, so it can’t be part of a guarded decision. The validator row is the one &lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;Part 2&lt;/a&gt; mentioned. Under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, Arc builds a fresh validator for every command so its read-model parameters belong to that command, and a validator the container hands out from another registration is refused:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Discoverable validator &apos;BorrowBookValidator&apos; cannot run while read protection is On because Arc did not construct it for this invocation. Let convention discovery register it as transient; do not use a scoped, singleton, factory or instance registration.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Any of the read-model-parameter rows can also be a read you only use as context; then mark it &lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt;, as the next section shows. An &lt;code dir=&quot;auto&quot;&gt;IMongoCollection&amp;#x3C;T&gt;&lt;/code&gt; can’t be marked that way: the collection itself is refused, so take the read model as an &lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt; parameter instead. Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/refusals/&quot;&gt;refusals page&lt;/a&gt; has the full list, including scopes, nested commands and declarations.&lt;/p&gt;
&lt;p&gt;A &lt;code dir=&quot;auto&quot;&gt;500&lt;/code&gt; carries its message in &lt;code dir=&quot;auto&quot;&gt;exceptionMessages&lt;/code&gt;, not in &lt;code dir=&quot;auto&quot;&gt;validationResults&lt;/code&gt;. In Development that’s the text above. Elsewhere, for model-bound commands, &lt;code dir=&quot;auto&quot;&gt;ArcOptions.ExposeExceptionDetails&lt;/code&gt; is &lt;code dir=&quot;auto&quot;&gt;false&lt;/code&gt; by default, and the caller gets this instead:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;An internal error occurred while processing the request. See server logs for details.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The full message goes to the server log, and the result keeps its &lt;code dir=&quot;auto&quot;&gt;correlationId&lt;/code&gt;, which is what you search the log for. These refusals don’t depend on timing: they come back the first time the command runs, so a test or a run in development finds them.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;declaring-a-read-advisory&quot;&gt;Declaring a read advisory&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Some reads are context, not part of the decision. Say the rejection message should name the book. The title comes from its own read model of the same book:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Queries&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookTitled&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Title&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookTitle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookTitled&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Title&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The validator takes it beside &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt;. A title that’s a moment stale changes no decision, so the read is declared advisory:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;FluentValidation&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; Isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Member&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Member&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowBookValidator&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CommandValidator&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowBookValidator&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;BookStock&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; stock&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Unprotected&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;only words the message; a stale title changes no decision&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;BookTitle&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; title&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;RuleFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;command &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Must&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;stock&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Available&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithMessage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;$&quot;&lt;/span&gt;&lt;span&gt;No copies of &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Title&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;??&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;this book&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&lt;span&gt; are available.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Without the attribute, &lt;code dir=&quot;auto&quot;&gt;BookTitle&lt;/code&gt; would be guarded like &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt;, and a retitle that lands between the read and the commit would refuse the borrow with two &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt; results. With it, the title is a plain read that guards nothing, and the retitle doesn’t conflict. &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; is still guarded.&lt;/p&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt; is in &lt;code dir=&quot;auto&quot;&gt;Cratis.Arc.Chronicle.ReadModels&lt;/code&gt;. Where you put it decides what it covers:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Place&lt;/th&gt;
&lt;th&gt;Covers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A parameter&lt;/td&gt;
&lt;td&gt;That parameter. The common case&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A read-model type&lt;/td&gt;
&lt;td&gt;Every parameter of that type, in every command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;Provide()&lt;/code&gt; method&lt;/td&gt;
&lt;td&gt;The method body only: &lt;code dir=&quot;auto&quot;&gt;IReadModels&lt;/code&gt; and other raw reads inside it, not the method’s parameters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A command&lt;/td&gt;
&lt;td&gt;The whole command runs as &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The reason is a sentence for a reviewer, and it goes to telemetry. Don’t use the attribute to silence a refusal you don’t understand. A refusal means Chronicle couldn’t guard that read exactly, and marking it advisory makes the rule depend on a stale value again.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;a-yes-that-should-have-been-a-no&quot;&gt;A yes that should have been a no&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Everything so far is about &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;. Under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;, the default, there are two ways a command approves something it should refuse, and neither one shows up as an error.&lt;/p&gt;
&lt;p&gt;The first is the snapshot read from &lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;Part 2&lt;/a&gt;. The validator checks &lt;code dir=&quot;auto&quot;&gt;Available &gt; 0&lt;/code&gt; against a value that’s already stale, the rule passes, and the commit doesn’t check the read.&lt;/p&gt;
&lt;p&gt;The second has nothing to do with concurrency. Validation results have a severity, and Arc lets the caller choose which severities block. A model-bound command reads it from the &lt;code dir=&quot;auto&quot;&gt;X-Allowed-Severity&lt;/code&gt; header. With a threshold, only results above it block, and &lt;code dir=&quot;auto&quot;&gt;3&lt;/code&gt; is &lt;code dir=&quot;auto&quot;&gt;Error&lt;/code&gt;, with nothing above it. Any HTTP client can send the header, and Arc’s TypeScript client sends it when you pass a severity to &lt;code dir=&quot;auto&quot;&gt;execute()&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ValidationResultSeverity&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/arc/validation&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;./BorrowBook&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;borrowIgnoringErrors&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;member&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;borrow&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;borrow&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;borrow&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;member&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;member&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;borrow&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;execute&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ValidationResultSeverity&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Error&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;For a book whose last copy is out, Arc drops the validator’s “No copies of this book are available.”, &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; runs, and &lt;code dir=&quot;auto&quot;&gt;BookBorrowed&lt;/code&gt; is appended for a book with no copy on the shelf. This is documented behaviour: severities are there for warnings a user can confirm, and Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/commands/validation-severity-filtering/&quot;&gt;severity filtering&lt;/a&gt; page says not to use them for integrity. A command can declare a floor the caller can’t lower with &lt;code dir=&quot;auto&quot;&gt;[BlockOnValidationSeverity]&lt;/code&gt;, but only if somebody remembers to add it to every command with a rule that must hold.&lt;/p&gt;
&lt;p&gt;Under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, both are closed, the second from Arc 22.108.0. The read is fresh and guarded, so a stale value gives a &lt;code dir=&quot;auto&quot;&gt;400 ReadChanged&lt;/code&gt; instead of a yes. And a command that declares read protection On, in the project or on the command, gets an &lt;code dir=&quot;auto&quot;&gt;Error&lt;/code&gt; floor: &lt;code dir=&quot;auto&quot;&gt;Error&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;Unknown&lt;/code&gt; results block whatever threshold the caller sends, and the caller can only let warnings and information through, which is what the threshold is for. The floor follows the declaration, so lowering &lt;code dir=&quot;auto&quot;&gt;ReadProtection:MaximumMode&lt;/code&gt; at runtime removes the guard but not the floor. A command with its own &lt;code dir=&quot;auto&quot;&gt;[BlockOnValidationSeverity]&lt;/code&gt; keeps that policy instead, so a &lt;code dir=&quot;auto&quot;&gt;Warning&lt;/code&gt; floor still blocks warnings. Commands declared &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;, without such an attribute, keep the caller’s threshold as before.&lt;/p&gt;
&lt;p&gt;The threshold applies to the results of filters, validators and &lt;code dir=&quot;auto&quot;&gt;Provide()&lt;/code&gt;. The &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt; from the commit isn’t one of them, so no threshold turns it into a success.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/a-yes-that-should-be-a-no.CEOCk2FC_QqamW.webp&quot; alt=&quot;A diagram titled A yes that should have been a no, in two frames. Under Read protection Off: a snapshot read lets stale stock pass; a caller that allows severity 3 gets the rule dropped and the borrow written; and today the fix is per command, declaring a floor on the command. Under Read protection On: a guarded fresh read gives 400 ReadChanged; a caller that allows severity 3 still gets the rule’s rejection; and below Error, warnings stay the caller’s choice. A band reads Under On, the read is guarded and errors block.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2200&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Two ways a command says yes under Off, and what On does with each. The Error floor under On needs Arc 22.108.0 or later.&lt;/em&gt;&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-build-tells-you-first&quot;&gt;The build tells you first&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Most &lt;code dir=&quot;auto&quot;&gt;500&lt;/code&gt;s can be seen in the code, and Arc’s analyzers report them at build time. This command reads the stock through &lt;code dir=&quot;auto&quot;&gt;IReadModels&lt;/code&gt; instead of taking it as a parameter:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowBookThroughReadModels&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; Isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Member&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IReadModels&lt;/span&gt;&lt;span&gt;&lt;span&gt; readModels&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;readModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;GetInstanceById&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookStock&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Member&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;It compiles, with a warning:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;warning ARCCHR0028: Command &apos;BorrowBookThroughReadModels&apos; calls &apos;GetInstanceById&apos; while read protection is On; this read is not proven protected. Take a read model as a parameter, use IDecisionReads.Get in Provide, or mark the method [Unprotected(&quot;why&quot;)].&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;At runtime it’s refused with &lt;code dir=&quot;auto&quot;&gt;ReadRefusedWhileReadsAreProtected&lt;/code&gt;, a &lt;code dir=&quot;auto&quot;&gt;500&lt;/code&gt; with the same three fixes. The analyzers that matter here:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Diagnostic&lt;/th&gt;
&lt;th&gt;Severity&lt;/th&gt;
&lt;th&gt;Reports&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/code-analysis/arcchr0024/&quot;&gt;ARCCHR0024&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Warning&lt;/td&gt;
&lt;td&gt;A read-model parameter whose shape can’t be protected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/code-analysis/arcchr0028/&quot;&gt;ARCCHR0028&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Warning&lt;/td&gt;
&lt;td&gt;A Chronicle read under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; that isn’t proven protected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/code-analysis/arcchr0033/&quot;&gt;ARCCHR0033&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Warning&lt;/td&gt;
&lt;td&gt;An aggregate and a read-model parameter of the same source&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/code-analysis/arcchr0023/&quot;&gt;ARCCHR0023&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Warning&lt;/td&gt;
&lt;td&gt;A read-model lookup key that isn’t proven&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/code-analysis/arcchr0029/&quot;&gt;ARCCHR0029&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Error&lt;/td&gt;
&lt;td&gt;Conflicting read-protection declarations on one command&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/code-analysis/arcchr0031/&quot;&gt;ARCCHR0031&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Error&lt;/td&gt;
&lt;td&gt;An invalid &lt;code dir=&quot;auto&quot;&gt;[LookUpBy]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/code-analysis/arcchr0037/&quot;&gt;ARCCHR0037&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Error&lt;/td&gt;
&lt;td&gt;A per-stream read model the command isn’t routed to&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/code-analysis/arcchr0011/&quot;&gt;ARCCHR0011&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Info&lt;/td&gt;
&lt;td&gt;Under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;, a plain read model in a command that produces events&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/code-analysis/arcchr0012/&quot;&gt;ARCCHR0012&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Info (Warning under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;An immediate append that bypasses a protected decision&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The diagnostics say “not proven” for a reason. They see what’s visible in the code, and some refusals depend on how a model is registered at runtime, so a clean build doesn’t mean no command will be refused. &lt;code dir=&quot;auto&quot;&gt;Info&lt;/code&gt; diagnostics are easy to miss in a build log. Raise ARCCHR0011 in a project with commands still under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;. ARCCHR0012 only fires for commands that are &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, use decision reads or carry &lt;code dir=&quot;auto&quot;&gt;[ProtectedDecision]&lt;/code&gt;, and raising it makes the &lt;code dir=&quot;auto&quot;&gt;[ProtectedDecision]&lt;/code&gt; and decision-read cases warnings too, so an immediate append there shows up at build time rather than at runtime:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;*.cs&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;dotnet_diagnostic.ARCCHR0011.severity&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; warning&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;dotnet_diagnostic.ARCCHR0012.severity&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; warning&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;With warnings treated as errors, each of them then fails the build instead of scrolling past.&lt;/p&gt;
&lt;aside aria-label=&quot;What to do when&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;What to do when&lt;/p&gt;&lt;div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code dir=&quot;auto&quot;&gt;400&lt;/code&gt; with &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt;:&lt;/strong&gt; read again and show the user the new state. Don’t put an error on a field, and don’t resubmit automatically.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code dir=&quot;auto&quot;&gt;400&lt;/code&gt; with &lt;code dir=&quot;auto&quot;&gt;ReadIncomplete&lt;/code&gt;:&lt;/strong&gt; submit again. The read didn’t reach that key’s latest events in three attempts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code dir=&quot;auto&quot;&gt;500&lt;/code&gt; with &lt;code dir=&quot;auto&quot;&gt;ReadCannotBeProtected&lt;/code&gt;:&lt;/strong&gt; reshape the model, read the parts separately, or mark the read &lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt; if it’s only context.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code dir=&quot;auto&quot;&gt;500&lt;/code&gt; with &lt;code dir=&quot;auto&quot;&gt;ReadRefusedWhileReadsAreProtected&lt;/code&gt;:&lt;/strong&gt; take the read model as a parameter, or use &lt;code dir=&quot;auto&quot;&gt;IDecisionReads.Get&lt;/code&gt; in &lt;code dir=&quot;auto&quot;&gt;Provide()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code dir=&quot;auto&quot;&gt;500&lt;/code&gt; with &lt;code dir=&quot;auto&quot;&gt;ImmediateAppendWhileReadsAreProtected&lt;/code&gt;:&lt;/strong&gt; return the event from &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt;, or use &lt;code dir=&quot;auto&quot;&gt;IEventLog.Transactional.Append&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code dir=&quot;auto&quot;&gt;500&lt;/code&gt; from a validator:&lt;/strong&gt; let convention discovery register it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Production shows “An internal error occurred”:&lt;/strong&gt; the message is redacted outside Development. Find the &lt;code dir=&quot;auto&quot;&gt;correlationId&lt;/code&gt; in the server log.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A rule must hold whatever the caller sends:&lt;/strong&gt; run the command under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; (Arc 22.108.0 or later). Under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;, add &lt;code dir=&quot;auto&quot;&gt;[BlockOnValidationSeverity]&lt;/code&gt; to it.&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/refusals/&quot;&gt;refusals page&lt;/a&gt; lists every refusal with its message, &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/reads/&quot;&gt;Reads&lt;/a&gt; explains what each kind of read becomes, and the frontend’s &lt;a href=&quot;https://www.cratis.io/arc/frontend/core/commands/command-result/&quot;&gt;command result&lt;/a&gt; page covers reasons and details. The next part is about getting an application that already runs from &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; to &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, by finding these refusals with &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; before they reach a user.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The examples need Arc 22.108.0 or later and Chronicle 19.68.0 or later.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;Previous: &lt;a href=&quot;https://blog.cratis.io/a-limit-for-one-month/&quot;&gt;Part 04 — A limit for one account and one month&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>arc</category><category>chronicle</category><category>concurrency</category><category>validation</category><category>typescript</category></item><item><title>A limit for one account and one month · Decisions that hold, Part 4</title><link>https://blog.cratis.io/a-limit-for-one-month/</link><guid isPermaLink="true">https://blog.cratis.io/a-limit-for-one-month/</guid><description>A monthly withdrawal limit depends on one month of one account. Declare that stream on the read model and route the command to it, and the guard covers that month only: a withdrawal in October conflicts, one in November doesn&apos;t.</description><pubDate>Wed, 28 Oct 2026 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://blog.cratis.io/the-bug-you-never-see/&quot;&gt;Decisions that hold&lt;/a&gt; · Part 04 of 11&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The previous two parts guarded a read model keyed by an entity: a book, a member. The guard watched that entity’s whole history for the event types the model folds. That’s the right boundary when the rule is about the whole entity. Many rules aren’t. A bank account may allow at most 5000 in withdrawals per calendar month. The rule depends on this account and this month, and nothing else.&lt;/p&gt;
&lt;p&gt;Neither of the obvious read models fits it. A model keyed by the account folds every month into one total, and a guard on the account’s withdrawals makes every withdrawal conflict with any concurrent one, whatever month it’s in. A model keyed by the month collides across accounts. What the rule needs is the account as the key, with the fold limited to one month.&lt;/p&gt;
&lt;p&gt;Chronicle has a place for that already. An event source definition can declare named streams, and an event appended to an account can carry a stream type (&lt;code dir=&quot;auto&quot;&gt;Transactions&lt;/code&gt;) and a stream id (&lt;code dir=&quot;auto&quot;&gt;2026-10&lt;/code&gt;). A read model can be declared on one such stream. Arc then reads it for the stream the command is routed to, and the guard it builds covers that stream only.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;declare-the-stream-on-the-read-model&quot;&gt;Declare the stream on the read model&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The examples assume read protection is On, as in new Cratis applications (see &lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;Part 2&lt;/a&gt;). Read protection is part of Arc for .NET. The definition, the event and the read model:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Queries&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSources&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;BankAccount&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventStream&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BankAccountEventSource&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IEventSource&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AccountId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MoneyWithdrawn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;decimal&lt;/span&gt;&lt;span&gt;&lt;span&gt; Amount&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventStream&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BankAccountEventSource&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MonthlyWithdrawals&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;AccountId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;AddFrom&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;MoneyWithdrawn&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;nameof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MoneyWithdrawn&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Amount&lt;/span&gt;&lt;span&gt;&lt;span&gt;))]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;decimal&lt;/span&gt;&lt;span&gt;&lt;span&gt; Total&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;MonthlyWithdrawals&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ForMonth&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;AccountId&lt;/span&gt;&lt;span&gt;&lt;span&gt; account&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventStreamId&lt;/span&gt;&lt;span&gt;&lt;span&gt; month&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IReadModels&lt;/span&gt;&lt;span&gt;&lt;span&gt; models&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; instance &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;models&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;GetInstanceById&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;MonthlyWithdrawals&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;account&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;month&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;instance&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;models&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Release&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;instance&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;There are two attributes with the same name here, and they do different things. &lt;code dir=&quot;auto&quot;&gt;[EventStream(&quot;Transactions&quot;)]&lt;/code&gt; on &lt;code dir=&quot;auto&quot;&gt;BankAccountEventSource&lt;/code&gt; declares that bank accounts have a &lt;code dir=&quot;auto&quot;&gt;Transactions&lt;/code&gt; stream. &lt;code dir=&quot;auto&quot;&gt;[EventStream&amp;#x3C;BankAccountEventSource&gt;(&quot;Transactions&quot;)]&lt;/code&gt; on the read model, from &lt;code dir=&quot;auto&quot;&gt;Cratis.Chronicle.ReadModels&lt;/code&gt;, says that &lt;code dir=&quot;auto&quot;&gt;MonthlyWithdrawals&lt;/code&gt; is folded from that one stream of that definition.&lt;/p&gt;
&lt;p&gt;The model keeps the account as its &lt;code dir=&quot;auto&quot;&gt;Id&lt;/code&gt;. The month isn’t part of the key; it selects which stream the fold reads. Declaring the stream also makes the model passive: Chronicle doesn’t keep a stored instance per account that could accumulate several months, and folds the requested stream when it’s read. &lt;code dir=&quot;auto&quot;&gt;ForMonth&lt;/code&gt; is a query for screens, and I’ll come back to it below.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;route-the-command-to-the-month&quot;&gt;Route the command to the month&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The command and the validator:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;FluentValidation&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventSource&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BankAccountEventSource&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventStreamId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;{Month}&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Withdraw&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;AccountId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Account&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Month&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;decimal&lt;/span&gt;&lt;span&gt;&lt;span&gt; Amount&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MoneyWithdrawn&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Amount&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WithdrawValidator&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CommandValidator&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Withdraw&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WithdrawValidator&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MonthlyWithdrawals&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; month&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;RuleFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;command &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Amount&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Must&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;amount &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;month&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Total&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;??&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0m&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;amount&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;#x3C;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;5000m&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithMessage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;The monthly withdrawal limit is 5000.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;[EventSource&amp;#x3C;BankAccountEventSource&gt;(&quot;Transactions&quot;)]&lt;/code&gt; routes the command’s events to the definition’s &lt;code dir=&quot;auto&quot;&gt;Transactions&lt;/code&gt; stream, and &lt;code dir=&quot;auto&quot;&gt;[EventStreamId(&quot;{Month}&quot;)]&lt;/code&gt; takes the stream id from the command’s &lt;code dir=&quot;auto&quot;&gt;Month&lt;/code&gt; property. &lt;code dir=&quot;auto&quot;&gt;AccountId&lt;/code&gt; derives from &lt;code dir=&quot;auto&quot;&gt;EventSourceId&lt;/code&gt;, so it’s the event source. &lt;code dir=&quot;auto&quot;&gt;MoneyWithdrawn&lt;/code&gt; from &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; is appended to &lt;code dir=&quot;auto&quot;&gt;BankAccount / Transactions / 2026-10&lt;/code&gt; for that account.&lt;/p&gt;
&lt;p&gt;The validator takes &lt;code dir=&quot;auto&quot;&gt;MonthlyWithdrawals&lt;/code&gt; as a plain parameter, the same way the book’s validator took &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt;. There’s no &lt;code dir=&quot;auto&quot;&gt;[LookUpBy]&lt;/code&gt; and no month argument. Arc sees that the model is declared on a stream, takes the source and the stream from the command’s route, and reads the model for that account in that month. Arc resolves &lt;code dir=&quot;auto&quot;&gt;{Month}&lt;/code&gt; before it builds the validator: a missing or blank &lt;code dir=&quot;auto&quot;&gt;Month&lt;/code&gt; comes back as a &lt;code dir=&quot;auto&quot;&gt;400&lt;/code&gt; with a rule failure on &lt;code dir=&quot;auto&quot;&gt;Month&lt;/code&gt; (“‘Month’ is required to read MonthlyWithdrawals”), and nothing is read.&lt;/p&gt;
&lt;p&gt;The rule lives in the validator, as before, and &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; only returns the event. With 4800 already withdrawn in October, a withdrawal of 500 in October fails with “The monthly withdrawal limit is 5000.” With 4800 withdrawn in September, the same withdrawal in October succeeds, because September’s events aren’t in October’s fold.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;what-it-guards&quot;&gt;What it guards&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The guard now has the stream in it. Written in the notation the Arc docs use (it’s not an API):&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;guard account: types=[MoneyWithdrawn], sourceType=BankAccount, streamType=Transactions, streamId=2026-10, after &amp;#x3C;position before the read&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Compared to the book’s guard, three dimensions are added: the event source type, the stream type and the stream id. A &lt;code dir=&quot;auto&quot;&gt;MoneyWithdrawn&lt;/code&gt; for this account that arrives in &lt;code dir=&quot;auto&quot;&gt;2026-10&lt;/code&gt; after the read conflicts. The command comes back with the same &lt;code dir=&quot;auto&quot;&gt;400&lt;/code&gt; as in Part 2, reason &lt;code dir=&quot;auto&quot;&gt;concurrencyViolation&lt;/code&gt;, detail &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt;, and nothing from it is written:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;MonthlyWithdrawals &apos;account-1&apos; changed after Withdraw read it. Nothing from this command was written; submit it again.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The message names the model and the account, not the month. A &lt;code dir=&quot;auto&quot;&gt;MoneyWithdrawn&lt;/code&gt; for this account in &lt;code dir=&quot;auto&quot;&gt;2026-11&lt;/code&gt; doesn’t conflict, and the command commits.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/one-month-one-guard.Bcax2yiX_Z1nhz4r.webp&quot; alt=&quot;A diagram titled One month, one guard. At the top, a card labeled Guard for MonthlyWithdrawals account-1 reads MoneyWithdrawn in Transactions 2026-10, after the position taken before the read. Below, three events each point to a result. MoneyWithdrawn arriving in 2026-10: conflict, nothing written. MoneyWithdrawn arriving in 2026-11: no conflict, another month. MoneyWithdrawn in 2026-10 written without the source type: not seen, neither folded nor guarded. A band reads Only the month the command is routed to.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2300&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Which concurrent withdrawals make an October withdrawal fail.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; also took &lt;code dir=&quot;auto&quot;&gt;MonthlyWithdrawals&lt;/code&gt;, it would get the same instance as the validator, from the same fold, under the same guard.&lt;/p&gt;
&lt;p&gt;Under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;, the same parameter still folds only that month, but it’s a plain read and guards nothing.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;keep-the-route-exact&quot;&gt;Keep the route exact&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The guard is only as narrow and as complete as the route, so a few things are worth checking.&lt;/p&gt;
&lt;p&gt;The command has to be routed to the same definition and stream as the model, with an explicit stream id. A command routed to another definition or stream, to all streams, or with no stream id, can’t read the model for its own month. Arc refuses that in every mode, &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; included, with &lt;code dir=&quot;auto&quot;&gt;ReadModelStreamNotOnCommandRoute&lt;/code&gt;, before anything is read. The &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/code-analysis/arcchr0037/&quot;&gt;ARCCHR0037&lt;/a&gt; analyzer reports it as a build error when the mismatch is visible in the source. &lt;code dir=&quot;auto&quot;&gt;[LookUpBy]&lt;/code&gt; on a per-stream parameter is refused too: the source always comes from the command’s route. To read another account or another month, use the stream overloads of &lt;code dir=&quot;auto&quot;&gt;IDecisionReads&lt;/code&gt; in &lt;code dir=&quot;auto&quot;&gt;Provide()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The event source type is part of both the fold and the guard. A &lt;code dir=&quot;auto&quot;&gt;MoneyWithdrawn&lt;/code&gt; written to &lt;code dir=&quot;auto&quot;&gt;Transactions/2026-10&lt;/code&gt; without the &lt;code dir=&quot;auto&quot;&gt;BankAccount&lt;/code&gt; source type isn’t folded into October’s total, and the guard doesn’t see it. Every writer that takes part in the rule has to use the definition’s route, and decide through a guard of its own. Routing commands with &lt;code dir=&quot;auto&quot;&gt;[EventSource&amp;#x3C;BankAccountEventSource&gt;(&quot;Transactions&quot;)]&lt;/code&gt; rather than repeating the strings keeps them aligned.&lt;/p&gt;
&lt;p&gt;The guard can also get wider than one month. Chronicle merges the reads a command makes on one event source into one guard, and keeps only the dimensions they agree on. If the validator also took a whole-source model of the same account, a count of all its withdrawals for example, the merged guard covers every month, and a November withdrawal makes the October command fail. Both reads come back as &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt;. Reading two months of the same stream drops the stream id. A &lt;code dir=&quot;auto&quot;&gt;Concurrency&lt;/code&gt; policy declared on the definition that includes the event source id but not both stream dimensions widens it the same way. &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/code-analysis/arcchr0038/&quot;&gt;ARCCHR0038&lt;/a&gt; reports the combinations it can see, as information.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/when-the-guard-widens.BTxOJ778_2uK4Fy.webp&quot; alt=&quot;A diagram titled When the guard widens, in two frames. Under Per-stream read only, the guard covers 2026-10 only for this account; a MoneyWithdrawn arriving in 2026-11 causes no conflict and the command commits. Under Plus a whole-source read, the guard covers every month for this account; the same MoneyWithdrawn arriving in 2026-11 makes the command fail with 400 ReadChanged and nothing written. A band reads A wider guard adds conflicts.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2300&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The same November withdrawal, with and without a whole-source read beside the monthly one.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A wider guard rejects commands that would have been fine. It still includes everything the narrower guard watched, so it adds conflicts and doesn’t drop any. If you need only this month’s state, take only the per-stream model. If you need the whole balance as well, keep both reads and accept the wider guard.&lt;/p&gt;
&lt;p&gt;The rest of the limits from Part 2 apply. &lt;code dir=&quot;auto&quot;&gt;Revise&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;Redact&lt;/code&gt; between the read and the commit aren’t detected. Other event sequences, services and data outside Chronicle aren’t guarded. &lt;code dir=&quot;auto&quot;&gt;EventStreamId.Default&lt;/code&gt; doesn’t narrow a fold to one id: in Chronicle it folds every id of the stream type, and Arc refuses it as a command route for a per-stream model.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;querying-one-month&quot;&gt;Querying one month&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;ForMonth&lt;/code&gt; on the model is a model-bound query for the screen that shows how much is left this month. It calls the stream overload of &lt;code dir=&quot;auto&quot;&gt;IReadModels.GetInstanceById&lt;/code&gt;, which takes the source and stream types from the declaration and the month from its argument. It returns October’s total for that account, or &lt;code dir=&quot;auto&quot;&gt;null&lt;/code&gt; if nothing was withdrawn in October.&lt;/p&gt;
&lt;p&gt;It’s a plain read. It guards nothing, and nothing it returns should decide a withdrawal; the validator does that. Chronicle refuses the reads that have no stream to fold: a key-only &lt;code dir=&quot;auto&quot;&gt;GetInstanceById&lt;/code&gt;, collections and snapshots, and &lt;code dir=&quot;auto&quot;&gt;Watch&lt;/code&gt;. A per-stream model has no stored instance per account, so there is nothing for those to return. Chronicle’s analyzer &lt;a href=&quot;https://www.cratis.io/chronicle/code-analysis/chr0064/&quot;&gt;CHR0064&lt;/a&gt; reports such reads when it can see them.&lt;/p&gt;
&lt;p&gt;If you call Chronicle without Arc, the same per-stream read model can be read as a decision read and guard an append directly. &lt;a href=&quot;https://www.cratis.io/chronicle/read-models/per-stream/&quot;&gt;Chronicle’s page on per-stream read models&lt;/a&gt; has that example, and Part 8 covers decision reads without Arc.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;or-no-model-at-all-a-stream-decision&quot;&gt;Or no model at all: a stream decision&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Some rules over a short stream don’t need folded state. “Has this report been approved this month?” is a question about whether one event exists. Arc’s stream decisions answer it from the raw events of the command’s stream:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Streams&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSequences&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSources&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Report&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventStream&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Approval&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; Concurrency &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyDimensions&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyDimensions&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventStreamType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyDimensions&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventStreamId&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReportEventSource&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IEventSource&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReportId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReportApproved&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventSource&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;ReportEventSource&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Approval&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventStreamId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;{Owner}:{Month}&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ApproveReport&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ReportId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Report&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Owner&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Month&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;StreamDecision&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Provide&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IStreamReads&lt;/span&gt;&lt;span&gt;&lt;span&gt; reads&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;reads&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ForCommand&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventsWithConcurrencyScopes&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;StreamDecision&lt;/span&gt;&lt;span&gt;&lt;span&gt; decision&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;decision&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Has&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;ReportApproved&lt;/span&gt;&lt;span&gt;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;decision&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;([])&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;decision&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReportApproved&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;reads.ForCommand()&lt;/code&gt; reads the events of this report in &lt;code dir=&quot;auto&quot;&gt;Approval/owner-1:2026-10&lt;/code&gt; and notes the position. &lt;code dir=&quot;auto&quot;&gt;decision.Append&lt;/code&gt; returns the events with a concurrency scope for that stream, and any event in that stream after the read refuses the append, of any type, including the first one. The refusal is a &lt;code dir=&quot;auto&quot;&gt;concurrencyViolation&lt;/code&gt; too, with a message about the event source instead of a read model. Another month doesn’t conflict. If the report is already approved, &lt;code dir=&quot;auto&quot;&gt;Append([])&lt;/code&gt; writes nothing, so a second approval is an identical retry rather than a second fact.&lt;/p&gt;
&lt;p&gt;The whole stream crosses the wire for the decision, so keep it short. When the rule needs a count or a folded status rather than “has it happened”, use a per-stream model. Choose one of the two for a command, not both: the validator reads before &lt;code dir=&quot;auto&quot;&gt;Provide()&lt;/code&gt; runs, and a stream decision’s scope, captured later, may not cover that read. Arc refuses it with &lt;code dir=&quot;auto&quot;&gt;ExplicitScopeDoesNotCoverReads&lt;/code&gt;, and &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/code-analysis/arcchr0036/&quot;&gt;ARCCHR0036&lt;/a&gt; warns about it at build time. Part 7 puts stream decisions next to the other mechanisms that aren’t guarded reads.&lt;/p&gt;
&lt;aside aria-label=&quot;What to do when&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;What to do when&lt;/p&gt;&lt;div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A rule depends on folded state of one stream on the command’s route&lt;/strong&gt; (a month, a period, a process): declare &lt;code dir=&quot;auto&quot;&gt;[EventStream&amp;#x3C;TSource&gt;(&quot;…&quot;)]&lt;/code&gt; on the read model, route the command with &lt;code dir=&quot;auto&quot;&gt;[EventSource&amp;#x3C;TSource&gt;(&quot;…&quot;)]&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;[EventStreamId(&quot;{…}&quot;)]&lt;/code&gt;, and take the model in the validator.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The rule is “has X happened in this short stream?”:&lt;/strong&gt; a stream decision, without a model.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The rule depends on the entity’s whole history&lt;/strong&gt;, a balance for example: a whole-source model. Combining it with a per-stream model gives a whole-source guard.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You need another month or another account:&lt;/strong&gt; the stream overloads of &lt;code dir=&quot;auto&quot;&gt;IDecisionReads&lt;/code&gt; in &lt;code dir=&quot;auto&quot;&gt;Provide()&lt;/code&gt;, not &lt;code dir=&quot;auto&quot;&gt;[LookUpBy]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Another month’s activity makes your command fail:&lt;/strong&gt; look for a second read on the same source or a declared &lt;code dir=&quot;auto&quot;&gt;Concurrency&lt;/code&gt; without both stream dimensions (ARCCHR0038).&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/scenarios/per-stream/&quot;&gt;one-stream scenario&lt;/a&gt; in the Arc docs has both examples, &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/commands/stream-decisions/&quot;&gt;stream decisions&lt;/a&gt; covers &lt;code dir=&quot;auto&quot;&gt;IStreamReads&lt;/code&gt; and testing on a route, and &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/how-it-works/&quot;&gt;How read protection works&lt;/a&gt; explains how guards from several reads merge. The next part is about the other side of a guard: what Arc says when it refuses a command, and what to do with each answer.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The examples need Arc 22.108.0 or later and Chronicle 19.71.0 or later.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;Previous: &lt;a href=&quot;https://blog.cratis.io/one-rule-two-entities/&quot;&gt;Part 03 — One rule, two entities, one append&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>arc</category><category>chronicle</category><category>concurrency</category><category>event-sourcing</category><category>validation</category></item><item><title>One rule, two entities, one append · Decisions that hold, Part 3</title><link>https://blog.cratis.io/one-rule-two-entities/</link><guid isPermaLink="true">https://blog.cratis.io/one-rule-two-entities/</guid><description>A member may hold three loans, and a book has one copy left. Two read models in one validator, one fact for each entity, one atomic append, and if either side changed after the read, nothing is written.</description><pubDate>Mon, 26 Oct 2026 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://blog.cratis.io/the-bug-you-never-see/&quot;&gt;Decisions that hold&lt;/a&gt; · Part 03 of 11&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The previous part ended with one book and one guard. &lt;code dir=&quot;auto&quot;&gt;BorrowBook&lt;/code&gt; takes a &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; read model in its validator, and with read protection On that read is folded fresh and guards the append: if a &lt;code dir=&quot;auto&quot;&gt;BookBorrowed&lt;/code&gt; for the same book lands between the read and the commit, nothing is written.&lt;/p&gt;
&lt;p&gt;Now add a rule the library already has on paper: a member may hold at most three loans. Member 1 has two books out, opens two tabs, and borrows a different book in each. If both requests read the member’s loan count before either commits, both see two loans and both approve a third. The guard from the previous part doesn’t help: it watches the book, and the competing borrow is of another book. The rule depends on two entities, so the decision has to hold for both.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;a-member-and-a-book&quot;&gt;A member and a book&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The rule needs a fact on the member to count, so the command writes one event to each entity, and the validator reads one model of each:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Queries&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSequences&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;FluentValidation&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopyAdded&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Member&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Member&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LoanTaken&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; Book&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LoanReturned&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; Book&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Increment&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;CopyAdded&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Decrement&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Increment&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Available&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MemberLoans&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Increment&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;LoanTaken&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Decrement&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;LoanReturned&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Active&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; Isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Member&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IEnumerable&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;EventForEventSourceId&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Member&lt;/span&gt;&lt;span&gt;)),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Member&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LoanTaken&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowBookValidator&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CommandValidator&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowBookValidator&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;LookUpBy&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;nameof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;))]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;BookStock&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; stock&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;LookUpBy&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;nameof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Member&lt;/span&gt;&lt;span&gt;&lt;span&gt;))]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;MemberLoans&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; loans&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;RuleFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;command &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Must&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;stock&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Available&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithMessage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;No copies of this book are available.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;RuleFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;command &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Member&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Must&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;loans&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;loans&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Active&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithMessage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;The member has reached the loan limit.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Read protection is part of Arc for .NET, and the project still has &lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;CratisReadProtection&gt;On&amp;#x3C;/CratisReadProtection&gt;&lt;/code&gt; from the previous part. Three things changed from the one-book version:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;MemberId&lt;/code&gt; derives from &lt;code dir=&quot;auto&quot;&gt;EventSourceId&lt;/code&gt; now. Before, the command only mentioned the member, so a plain concept was enough. Now it appends to the member, so the member is an event source with its own history.&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; returns &lt;code dir=&quot;auto&quot;&gt;EventForEventSourceId&lt;/code&gt; values. Each one names the event source it goes to, so the command doesn’t need a single event source id, and Arc doesn’t need &lt;code dir=&quot;auto&quot;&gt;ICanProvideEventSourceId&lt;/code&gt; to pick one.&lt;/li&gt;
&lt;li&gt;The validator takes two read models, and &lt;code dir=&quot;auto&quot;&gt;[LookUpBy]&lt;/code&gt; names the command property that supplies each key. &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; is read for &lt;code dir=&quot;auto&quot;&gt;Isbn&lt;/code&gt;, and &lt;code dir=&quot;auto&quot;&gt;MemberLoans&lt;/code&gt; for &lt;code dir=&quot;auto&quot;&gt;Member&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Under On, each read-model parameter is its own decision read. Chronicle notes the log’s position, folds that one key’s history, and enrolls a guard before the validator sees the value. Two reads give two guards, one per key:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;guard isbn-1:   types=[CopyAdded, BookBorrowed, BookReturned], after &amp;#x3C;tail before the BookStock read&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;guard member-1: types=[LoanTaken, LoanReturned], after &amp;#x3C;tail before the MemberLoans read&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;That is notation, not output: one line per guard, with the key, the event types the model folds, and the position captured before the fold. Arc commits both events as one atomic append, and the kernel checks both guards with it. If either one is violated, neither event is written.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/two-facts-one-append.BJVHuFia_1KlHn4.webp&quot; alt=&quot;Two guard cards at the top: on isbn-1 for BookStock with CopyAdded, BookBorrowed and BookReturned, and on member-1 for MemberLoans with LoanTaken and LoanReturned. Each points down to the event appended to that key, BookBorrowed to isbn-1 and LoanTaken to member-1, inside one box labelled one atomic append, both events or neither. Below, a green card reads neither key changed, both events are written, and a red card reads either key changed, nothing is written.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2200&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Each read guards its own key. Both guards are checked with the one append.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Back to the two tabs. Both requests read &lt;code dir=&quot;auto&quot;&gt;MemberLoans&lt;/code&gt; with &lt;code dir=&quot;auto&quot;&gt;Active = 2&lt;/code&gt;, and both pass the validator. The first to commit appends &lt;code dir=&quot;auto&quot;&gt;BookBorrowed&lt;/code&gt; to its book and &lt;code dir=&quot;auto&quot;&gt;LoanTaken&lt;/code&gt; to member 1. The second commit carries a guard on member 1 that says “no &lt;code dir=&quot;auto&quot;&gt;LoanTaken&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;LoanReturned&lt;/code&gt; after the position I read”, and the first request just broke it. The kernel rejects the second append, and its book keeps its copy. The caller gets a &lt;code dir=&quot;auto&quot;&gt;400&lt;/code&gt; with the reason &lt;code dir=&quot;auto&quot;&gt;concurrencyViolation&lt;/code&gt;, the detail &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt;, and a message that names the model and key that moved:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;MemberLoans &apos;member-1&apos; changed after BorrowBook read it. Nothing from this command was written; submit it again.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If instead another member took the last copy of the same book, the book’s guard is the one that fires, and the message says &lt;code dir=&quot;auto&quot;&gt;BookStock &apos;isbn-1&apos; changed after BorrowBook read it.&lt;/code&gt; with the same ending. The validation result’s state carries &lt;code dir=&quot;auto&quot;&gt;readModel&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;key&lt;/code&gt; as separate values, so a client can tell which side changed without parsing the text. Arc and Chronicle do not re-run the command. The caller reads again, and if it submits again, the validator sees three loans and refuses with “The member has reached the loan limit.”, an ordinary rule failure.&lt;/p&gt;
&lt;p&gt;Events that don’t touch either guard leave the command alone. Another member’s borrow of a different book, or an event on member 1 that &lt;code dir=&quot;auto&quot;&gt;MemberLoans&lt;/code&gt; doesn’t fold, lets both events commit as usual. Member 1 borrowing a different book does conflict: that borrow appends &lt;code dir=&quot;auto&quot;&gt;LoanTaken&lt;/code&gt; to member 1.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;each-entity-gets-its-own-fact&quot;&gt;Each entity gets its own fact&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;BookBorrowed&lt;/code&gt; goes to the book and &lt;code dir=&quot;auto&quot;&gt;LoanTaken&lt;/code&gt; goes to the member. It is tempting to write &lt;code dir=&quot;auto&quot;&gt;BookBorrowed&lt;/code&gt; to both and have &lt;code dir=&quot;auto&quot;&gt;MemberLoans&lt;/code&gt; count it. Don’t. A model-bound projection folds an event into the instance keyed by the event source it was appended to, so every model that counts &lt;code dir=&quot;auto&quot;&gt;BookBorrowed&lt;/code&gt; would see both copies. A &lt;code dir=&quot;auto&quot;&gt;BookBorrowed&lt;/code&gt; appended to member 1 gives member 1 a &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; of its own, with &lt;code dir=&quot;auto&quot;&gt;Available&lt;/code&gt; at -1. Two event types keep each model to its own entity’s events.&lt;/p&gt;
&lt;p&gt;They are also two different facts. “A copy left the shelf” belongs in the book’s history, and “the member took a loan” belongs in the member’s. Returning a book appends &lt;code dir=&quot;auto&quot;&gt;BookReturned&lt;/code&gt; to the book and &lt;code dir=&quot;auto&quot;&gt;LoanReturned&lt;/code&gt; to the member, the same way.&lt;/p&gt;
&lt;p&gt;If you know the &lt;a href=&quot;https://dcb.events/examples/course-subscriptions/&quot;&gt;dynamic consistency boundary&lt;/a&gt;, this is where Chronicle differs from it. In DCB, one event can carry a tag for each entity it concerns, and one query reads both. In Chronicle every event belongs to exactly one event source, so a fact about two entities is two events in one atomic append, and each read model reads its own entity’s events. Chronicle’s &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/chronicle/#when-one-fact-becomes-two-events&quot;&gt;DCB page&lt;/a&gt; says when two events for one fact are the right answer, and when to look for a form with one event instead.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;choosing-the-key&quot;&gt;Choosing the key&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;A read-model parameter reads the instance whose &lt;code dir=&quot;auto&quot;&gt;Id&lt;/code&gt; equals a key taken from the command. Under On, Arc picks that key in this order:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The command property named by &lt;code dir=&quot;auto&quot;&gt;[LookUpBy(nameof(...))]&lt;/code&gt; on the parameter.&lt;/li&gt;
&lt;li&gt;Without it, the one command property whose type equals the model’s &lt;code dir=&quot;auto&quot;&gt;Id&lt;/code&gt; type.&lt;/li&gt;
&lt;li&gt;If several properties match, the command fails with &lt;code dir=&quot;auto&quot;&gt;AmbiguousReadModelLookup&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If none matches, the command’s event source id.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; has an &lt;code dir=&quot;auto&quot;&gt;Isbn Id&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;MemberLoans&lt;/code&gt; a &lt;code dir=&quot;auto&quot;&gt;MemberId Id&lt;/code&gt;, and &lt;code dir=&quot;auto&quot;&gt;BorrowBook&lt;/code&gt; has exactly one property of each type, so under On the second rule would find both keys on its own. I still write &lt;code dir=&quot;auto&quot;&gt;[LookUpBy]&lt;/code&gt;, for two reasons. It works the same in every mode, while under Off and Measure a parameter without it reads the command’s event source id. And it survives the next property: add a &lt;code dir=&quot;auto&quot;&gt;MemberId ReservedFor&lt;/code&gt; to the command, and the type rule no longer has a single answer. A command with two properties of the model’s &lt;code dir=&quot;auto&quot;&gt;Id&lt;/code&gt; type and no &lt;code dir=&quot;auto&quot;&gt;[LookUpBy]&lt;/code&gt; fails with &lt;code dir=&quot;auto&quot;&gt;AmbiguousReadModelLookup&lt;/code&gt;, a &lt;code dir=&quot;auto&quot;&gt;500&lt;/code&gt; whose message names both properties and asks you to select one with &lt;code dir=&quot;auto&quot;&gt;[LookUpBy]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;[LookUpBy]&lt;/code&gt; goes on the parameter, also on a validator constructor, and names a property of the command. The property’s type doesn’t have to match the model’s &lt;code dir=&quot;auto&quot;&gt;Id&lt;/code&gt; type: Arc converts the value to the key, so an &lt;code dir=&quot;auto&quot;&gt;Isbn&lt;/code&gt; property can select a model with an &lt;code dir=&quot;auto&quot;&gt;EventSourceId Id&lt;/code&gt;. When the second key isn’t on the command at all, because it’s computed or looked up, read it with &lt;code dir=&quot;auto&quot;&gt;IDecisionReads.Get&lt;/code&gt; in &lt;code dir=&quot;auto&quot;&gt;Provide()&lt;/code&gt;. That read is guarded in the same way. The &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/reads/#choose-the-key-with-lookupby&quot;&gt;reads page&lt;/a&gt; has the conversion rules.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;a-course-and-a-student&quot;&gt;A course and a student&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The canonical example for a rule across two entities is &lt;a href=&quot;https://dcb.events/examples/course-subscriptions/&quot;&gt;course subscription&lt;/a&gt;: a course has a fixed number of seats, and a student can join at most three courses. In Arc it’s the same shape as the library:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Queries&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSequences&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;FluentValidation&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CourseId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;StudentId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CourseDefined&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Capacity&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SeatTaken&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;StudentId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Student&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CourseJoined&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;CourseId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Course&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;FromEvent&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;CourseDefined&lt;/span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CourseSeats&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;CourseId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Capacity&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Increment&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;SeatTaken&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Taken&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;StudentCourses&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;StudentId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Increment&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;CourseJoined&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Count&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SubscribeToCourse&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;CourseId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Course&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;StudentId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Student&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IEnumerable&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;EventForEventSourceId&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Course&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SeatTaken&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Student&lt;/span&gt;&lt;span&gt;)),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Student&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CourseJoined&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Course&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SubscribeToCourseValidator&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CommandValidator&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;SubscribeToCourse&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SubscribeToCourseValidator&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;LookUpBy&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;nameof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;SubscribeToCourse&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Course&lt;/span&gt;&lt;span&gt;&lt;span&gt;))]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CourseSeats&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; course&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;LookUpBy&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;nameof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;SubscribeToCourse&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Student&lt;/span&gt;&lt;span&gt;&lt;span&gt;))]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;StudentCourses&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; student&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;RuleFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;command &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Course&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Must&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;course&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;not&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithMessage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;The course does not exist.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Must&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;course&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;course&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Taken&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;course&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Capacity&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithMessage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;The course is full.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;RuleFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;command &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Student&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Must&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;student&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;student&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Count&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithMessage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;The student is already in three courses.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;guard course-1:  types=[CourseDefined, SeatTaken], after &amp;#x3C;tail before the CourseSeats read&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;guard student-1: types=[CourseJoined], after &amp;#x3C;tail before the StudentCourses read&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;[FromEvent&amp;#x3C;CourseDefined&gt;]&lt;/code&gt; sets &lt;code dir=&quot;auto&quot;&gt;Capacity&lt;/code&gt; from the event with the same property name. A &lt;code dir=&quot;auto&quot;&gt;SeatTaken&lt;/code&gt; on the course after the read rejects the command with &lt;code dir=&quot;auto&quot;&gt;CourseSeats &apos;course-1&apos; changed…&lt;/code&gt;, and a &lt;code dir=&quot;auto&quot;&gt;CourseJoined&lt;/code&gt; on the student, from the same student subscribing to another course, rejects it with &lt;code dir=&quot;auto&quot;&gt;StudentCourses &apos;student-1&apos; changed…&lt;/code&gt;. Neither case writes anything.&lt;/p&gt;
&lt;p&gt;A decision guards each key it reads, whether or not it writes there. A command that reads a member’s standing and appends only to the book is still rejected if the member is suspended between its read and its commit. The guard is built from the read, not from the append.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-trap-a-model-keyed-by-an-event-property&quot;&gt;The trap: a model keyed by an event property&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;There is a shorter way to count loans that looks right. &lt;code dir=&quot;auto&quot;&gt;BookBorrowed&lt;/code&gt; already names the member, so a model can fold the book’s events and key them by that property:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Queries&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;FromEvent&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nameof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Member&lt;/span&gt;&lt;span&gt;))]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MemberLoans&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Increment&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Active&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;As a query model this is fine. As a decision it can’t be guarded. A guard covers the events of one event source, and this model’s events live on the books’ event sources, one per book. A borrow of any other book by the same member changes the count, and there is no key a guard could watch to see it.&lt;/p&gt;
&lt;p&gt;Arc says so twice. The build reports &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/code-analysis/arcchr0024/&quot;&gt;ARCCHR0024&lt;/a&gt; as a warning on the validator parameter, and under On the command is refused with a &lt;code dir=&quot;auto&quot;&gt;500&lt;/code&gt; and writes nothing. In Development the response carries this message; elsewhere the client gets a generic error and the message goes to the server log:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;BorrowBook reads &apos;loans&apos; (MemberLoans) keyed by an event property, so read protection cannot guard it. If it is only context, mark it [Unprotected(&quot;why&quot;)]. Otherwise append a fact to the entity it is keyed by, or use a constraint.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The fix is the first example: append &lt;code dir=&quot;auto&quot;&gt;LoanTaken&lt;/code&gt; to the member, and key the model by the member’s own events. Marking the read &lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt; would let the command run, with the loan count as an unguarded snapshot. That is right only if the count is context, not the rule.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;what-this-does-not-cover&quot;&gt;What this does not cover&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The guards cover exactly the keys the command read. That has two consequences worth checking in your own rules.&lt;/p&gt;
&lt;p&gt;If the set of keys a rule counts over can grow, the new keys are outside every guard. Say each loan were its own event source, and the limit counted open loans across them. A loan created after the read is on a key nobody read, so no guard sees it. Put such a limit on one key that receives every relevant fact, which is what &lt;code dir=&quot;auto&quot;&gt;MemberLoans&lt;/code&gt; on the member does.&lt;/p&gt;
&lt;p&gt;A rule also holds only as far as every writer that decides on it reads through a guard. An import job that appends &lt;code dir=&quot;auto&quot;&gt;LoanTaken&lt;/code&gt; to a member without reading &lt;code dir=&quot;auto&quot;&gt;MemberLoans&lt;/code&gt; doesn’t check the limit. If its event lands inside our command’s window, our guard on the member detects it and our command is the one rejected. If it lands after our commit, nothing checks it at all.&lt;/p&gt;
&lt;p&gt;The rest of the limits from the previous part apply to each read here: a &lt;code dir=&quot;auto&quot;&gt;Revise&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;Redact&lt;/code&gt; between read and commit is not detected, other event sequences and data outside Chronicle are not guarded, and with read protection Off, the default, both reads are plain snapshots that guard nothing.&lt;/p&gt;
&lt;aside aria-label=&quot;What to do when&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;What to do when&lt;/p&gt;&lt;div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A rule reads two entities and writes to both:&lt;/strong&gt; two read-model parameters on the validator, each with &lt;code dir=&quot;auto&quot;&gt;[LookUpBy]&lt;/code&gt;, and &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; returning one &lt;code dir=&quot;auto&quot;&gt;EventForEventSourceId&lt;/code&gt; per entity.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The second key isn’t on the command:&lt;/strong&gt; read it with &lt;code dir=&quot;auto&quot;&gt;IDecisionReads.Get&lt;/code&gt; in &lt;code dir=&quot;auto&quot;&gt;Provide()&lt;/code&gt;; it is guarded the same way.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You want one event type for both entities:&lt;/strong&gt; use two. A model folds every event of its types, keyed by the source it was appended to.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A model is keyed by a property inside another entity’s events:&lt;/strong&gt; append a fact to that entity instead. Under On the read is refused, and &lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt; only turns it back into a snapshot.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The set of keys can grow:&lt;/strong&gt; move the count onto one key that receives every fact, or the new keys are not guarded.&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/scenarios/two-entities/&quot;&gt;two-entities scenario&lt;/a&gt; in the Arc docs has both examples, and &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/refusals/&quot;&gt;refusals&lt;/a&gt; lists the 500s with their fixes. A rule over one account and one month, read from a single stream, is the next shape.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The examples need Arc 22.108.0 or later and Chronicle 19.68.0 or later.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;Previous: &lt;a href=&quot;https://blog.cratis.io/the-read-model-said-yes/&quot;&gt;Part 02 — The read model said yes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>arc</category><category>chronicle</category><category>concurrency</category><category>event-sourcing</category><category>validation</category></item><item><title>The read model said yes · Decisions that hold, Part 2</title><link>https://blog.cratis.io/the-read-model-said-yes/</link><guid isPermaLink="true">https://blog.cratis.io/the-read-model-said-yes/</guid><description>A command that reads a read model and then appends can approve the same last copy twice. One project setting turns that read into a guard: the same command, the same validator, and the loser of the race gets a 400 that says nothing was written.</description><pubDate>Thu, 22 Oct 2026 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://blog.cratis.io/the-bug-you-never-see/&quot;&gt;Decisions that hold&lt;/a&gt; · Part 02 of 11&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.cratis.io/the-bug-you-never-see/&quot;&gt;Part 1&lt;/a&gt; was about the check that passes twice: a rule reads state, decides, and writes, and two requests can both pass the check before either writes. This part is that bug in an event-sourced application, written the way most of us write the command first, and the one project setting that makes Arc and Chronicle guard it.&lt;/p&gt;
&lt;p&gt;A library lends a book only while a copy is on the shelf. In an event-sourced system the stock is a fold over the book’s events, and Chronicle can keep it as a read model:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Queries&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Concepts&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ConceptAs&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopyAdded&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Member&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Member&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Increment&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;CopyAdded&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Decrement&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Increment&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Available&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The command most of us write first takes that read model and checks it. The check belongs in a validator, because “may this command proceed” is what validators are for:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;FluentValidation&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; Isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Member&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Member&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowBookValidator&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CommandValidator&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowBookValidator&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BookStock&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; stock&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;RuleFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;command &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Must&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;stock&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Available&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithMessage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;No copies of this book are available.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;Isbn&lt;/code&gt; derives from &lt;code dir=&quot;auto&quot;&gt;EventSourceId&lt;/code&gt;, so it’s the command’s event source id and the key Arc reads &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; by. &lt;code dir=&quot;auto&quot;&gt;MemberId&lt;/code&gt; is a &lt;code dir=&quot;auto&quot;&gt;ConceptAs&amp;#x3C;Guid&gt;&lt;/code&gt;: it refers to the member, and this command doesn’t append to the member. &lt;code dir=&quot;auto&quot;&gt;BookStock?&lt;/code&gt; is nullable because a book with no events has no read model yet. A non-nullable parameter fails the command with &lt;code dir=&quot;auto&quot;&gt;ReadModelDoesNotExistForCommand&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;Arc looks up &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; by the book’s key, builds the validator with it, and runs the rule. &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; returns an event, and when the command succeeds Arc commits that event to Chronicle. Nothing in this path connects the commit to the value of &lt;code dir=&quot;auto&quot;&gt;Available&lt;/code&gt; that the validator looked at.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;two-requests-for-the-last-copy&quot;&gt;Two requests for the last copy&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Take a book with one copy left and two members who press &lt;strong&gt;Borrow&lt;/strong&gt; at about the same time:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;request A                                  request B&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;read BookStock: Available = 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                                           &lt;/span&gt;&lt;/span&gt;&lt;span&gt;read BookStock: Available = 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;validate: 1 &gt; 0, Handle: BookBorrowed&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;commit: read tail, append, success&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                                           &lt;/span&gt;&lt;/span&gt;&lt;span&gt;validate: 1 &gt; 0, Handle: BookBorrowed&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                                           &lt;/span&gt;&lt;/span&gt;&lt;span&gt;commit: read tail, append, success&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;BookStock.Available is now -1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Both commands succeed, both &lt;code dir=&quot;auto&quot;&gt;BookBorrowed&lt;/code&gt; events are in the log, and the stock folds to -1.&lt;/p&gt;
&lt;p&gt;Arc does run a concurrency check when it commits to an event source that already has events. By default the .NET client reads the event source’s tail when the events are appended and sends that position along, so the kernel rejects the append if another event landed between that tail read and the write. That window opens after the validator and &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; have decided. It catches two commits that overlap, so when both requests arrive at exactly the same moment it can reject one of them. With request B a few milliseconds behind A, as above, B reads the tail after A’s event is already there, and the check passes.&lt;/p&gt;
&lt;p&gt;It doesn’t even take concurrency. &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; here is a materialized read model, which Chronicle updates after the append returns, not with it. A second request sent after the first one has completed can still read &lt;code dir=&quot;auto&quot;&gt;Available = 1&lt;/code&gt; and be approved.&lt;/p&gt;
&lt;p&gt;The same holds for the other places a command can read state on its way to the append. A read-model parameter on &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; gets the same snapshot as the validator. A passive projection folds fresh from the events when it’s read, so it doesn’t lag, but it records no position either, and the append that follows isn’t conditioned on it.&lt;/p&gt;
&lt;p&gt;None of this is new. &lt;a href=&quot;https://blog.cratis.io/rules-that-hold-when-you-write/&quot;&gt;&lt;em&gt;Rules that hold when you write&lt;/em&gt;&lt;/a&gt; and &lt;a href=&quot;https://blog.cratis.io/validation-all-the-way-down/&quot;&gt;&lt;em&gt;Validation all the way down&lt;/em&gt;&lt;/a&gt; described the snapshot, and the per-command opt-in with &lt;code dir=&quot;auto&quot;&gt;[ProtectedDecision]&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;DecisionRead&amp;#x3C;T&gt;&lt;/code&gt;. What’s new is that the fix no longer needs a different command.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;turning-the-read-into-a-guard&quot;&gt;Turning the read into a guard&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Arc has a mode for this, called read protection. It’s &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; by default, and under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; an injected read model is a plain read, as above. The next major version of Arc turns it &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; by default, and you’ll still be able to turn it off for one command with &lt;code dir=&quot;auto&quot;&gt;[ReadProtection(ReadProtectionMode.Off)]&lt;/code&gt; or for one read with &lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt; (&lt;a href=&quot;https://github.com/Cratis/Arc/issues/3255&quot;&gt;Cratis/Arc#3255&lt;/a&gt;). Set it to &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; in the project that contains your commands, or in a &lt;code dir=&quot;auto&quot;&gt;Directory.Build.props&lt;/code&gt; that covers several:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PropertyGroup&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;CratisReadProtection&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;On&lt;/span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;CratisReadProtection&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;PropertyGroup&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The value is compiled into the assembly, so analyzers and tests see the mode that runs in production. It must be &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;. Anything else fails the build with &lt;code dir=&quot;auto&quot;&gt;CratisReadProtection must be Off, Measure, or On.&lt;/code&gt; To turn it on for one command instead, put &lt;code dir=&quot;auto&quot;&gt;[ReadProtection(ReadProtectionMode.On)]&lt;/code&gt; (namespace &lt;code dir=&quot;auto&quot;&gt;Cratis.Arc.Commands&lt;/code&gt;) on the command; a command-level value overrides the assembly’s.&lt;/p&gt;
&lt;p&gt;The command and the validator above don’t change. What changes is when the position is taken and what the commit checks against it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Arc starts a unit of work for the command and turns on read protection for the whole invocation, before any filter or validator runs. The unit of work collects the command’s events and its guards, and only Arc’s command pipeline may commit it: code inside the command can’t commit it early or roll it back.&lt;/li&gt;
&lt;li&gt;Arc builds the validator inside that unit. For its &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; parameter, Chronicle first captures the position of the event log, and only then folds &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; from the book’s own events, in a fresh session straight from the event log. The materialized copy isn’t used.&lt;/li&gt;
&lt;li&gt;The read is enrolled in the unit of work as a guard: no event of the types &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; is built from, on this book, after that position.&lt;/li&gt;
&lt;li&gt;The validator decides from that instance, and &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; returns &lt;code dir=&quot;auto&quot;&gt;BookBorrowed&lt;/code&gt;. If &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; took &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; too, it would get the same instance under the same guard.&lt;/li&gt;
&lt;li&gt;Arc commits the unit of work, which sends the command’s events and the guards to the kernel in one append. The kernel rejects the append if anything matching a guard arrived after the position, and nothing from the command is written.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Taking the position before the fold is what makes the guard sound. An event that lands during the fold, or after it, is after the position, so it’s detected. If events keep arriving while it folds, Chronicle folds again; the read makes up to three attempts.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/last-copy-twice.H9WYX2wZ_Z2sjv7x.webp&quot; alt=&quot;A diagram titled One copy, two borrowers, in two frames. Under Read protection Off, request A and request B both read Available = 1 and both commit, and the stock folds to minus one with two BookBorrowed events for one copy. Under Read protection On, request A reads Available = 1 and commits, request B is refused with 400 ReadChanged and nothing is written, and the stock ends at zero with one BookBorrowed event. A band reads Same command, same validator, one project setting.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2200&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The same two requests under each mode.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In the interleaving above, request B now loses:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;request A                                  request B&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;position p, fold BookStock: Available = 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                                           &lt;/span&gt;&lt;/span&gt;&lt;span&gt;position p, fold BookStock: Available = 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;validate: 1 &gt; 0, Handle: BookBorrowed&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;commit: nothing after p, success&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                                           &lt;/span&gt;&lt;/span&gt;&lt;span&gt;validate: 1 &gt; 0, Handle: BookBorrowed&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                                           &lt;/span&gt;&lt;/span&gt;&lt;span&gt;commit: BookBorrowed after p, refused&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;BookStock.Available is now 0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If B starts late enough to fold A’s event, it gets the business rejection instead, “No copies of this book are available.” Either way the book has one &lt;code dir=&quot;auto&quot;&gt;BookBorrowed&lt;/code&gt; event and the stock ends at zero.&lt;/p&gt;
&lt;p&gt;The Arc docs write a guard as one line. It’s a notation, not an API:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;guard isbn-1: types=[CopyAdded, BookBorrowed, BookReturned], after &amp;#x3C;position before the read&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The filter is the key and the model’s event types, nothing more. A borrow of the same book conflicts. An event on the same book that &lt;code dir=&quot;auto&quot;&gt;BookStock&lt;/code&gt; doesn’t fold, a rename for example, doesn’t. A borrow of another book doesn’t either. A model that doesn’t exist yet is guarded too: the parameter is &lt;code dir=&quot;auto&quot;&gt;null&lt;/code&gt;, and a first event of the model’s types that arrives after the read conflicts. That’s how “only if it doesn’t exist yet” holds.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/what-the-guard-watches.BGtXGTZy_Z2jVW1z.webp&quot; alt=&quot;A diagram titled What the guard watches. At the top, a card labeled Guard for BookStock isbn-1 lists CopyAdded, BookBorrowed and BookReturned, after the position taken before the read. Below, three events each point to a result. BookBorrowed arriving for isbn-1: conflict, nothing written. BookRenamed arriving for isbn-1: no conflict, BookStock does not fold it. BookBorrowed arriving for isbn-2: no conflict, another key. A band reads The model’s event types, on the key it read.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2300&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Which concurrent events make the command fail.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Nothing is locked. Two borrowers of the same book both run to the commit, and the commit is where one of them may be refused.&lt;/p&gt;
&lt;p&gt;Under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, Arc builds a fresh validator for every command so that its read-model parameters are guards in that command’s unit of work. That’s why the validator has to be registered by convention, as a transient, which is what Arc does when you don’t register it yourself. A validator registered by hand as scoped, singleton, a factory or an instance is refused. Part 5 has the refusals and their fixes.&lt;/p&gt;
&lt;p&gt;If you have commands marked &lt;code dir=&quot;auto&quot;&gt;[ProtectedDecision]&lt;/code&gt; that read through &lt;code dir=&quot;auto&quot;&gt;DecisionRead&amp;#x3C;T&gt;&lt;/code&gt;: under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; you don’t need &lt;code dir=&quot;auto&quot;&gt;[ProtectedDecision]&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;DecisionRead&amp;#x3C;T&gt;&lt;/code&gt;; they keep working.&lt;/p&gt;
&lt;p&gt;Read protection is part of Arc for .NET.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;what-the-caller-sees&quot;&gt;What the caller sees&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The refused command returns a &lt;code dir=&quot;auto&quot;&gt;400&lt;/code&gt;. Its validation result has the reason &lt;code dir=&quot;auto&quot;&gt;concurrencyViolation&lt;/code&gt; (&lt;code dir=&quot;auto&quot;&gt;ValidationResultReason.ConcurrencyViolation&lt;/code&gt; in .NET), the detail &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt;, a state object with the model and the key (&lt;code dir=&quot;auto&quot;&gt;{&quot;readModel&quot;:&quot;BookStock&quot;,&quot;key&quot;:&quot;isbn-1&quot;}&lt;/code&gt;), and this message:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;BookStock &apos;isbn-1&apos; changed after BorrowBook read it. Nothing from this command was written; submit it again.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Arc and Chronicle don’t re-run the command. The read itself makes up to three attempts at the fold, but once the validator and &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; have decided, a conflict ends the command. The state the decision rested on has changed, and deciding again from new state is the caller’s call: read again, show the user, and submit again if it still makes sense. Resubmitting blindly in a loop would undo the point of the guard. The message doesn’t say which event caused the conflict.&lt;/p&gt;
&lt;p&gt;A rejection by the validator itself is a different result. “No copies of this book are available.” is an ordinary rule failure, not a &lt;code dir=&quot;auto&quot;&gt;concurrencyViolation&lt;/code&gt;. It writes nothing, so it needs no guard.&lt;/p&gt;
&lt;p&gt;Part 5 goes through every refusal, the &lt;code dir=&quot;auto&quot;&gt;500&lt;/code&gt;s that mean the code can’t be guarded, and how a UI tells a changed read from a field error. If you want to see the race in a test now, Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/scenarios/testing/&quot;&gt;Test the race&lt;/a&gt; page puts a competing append between the read and the commit. Part 9 is about that.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;where-the-guard-stops&quot;&gt;Where the guard stops&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;A guard covers one key’s history, for the event types the model folds, from the position taken before the read. Some things are outside it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;Revise&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;Redact&lt;/code&gt; between the read and the commit aren’t detected, because they don’t move the tail. Chronicle refuses them inside a protected invocation.&lt;/li&gt;
&lt;li&gt;Services, HTTP calls, other databases and other event sequences aren’t guarded.&lt;/li&gt;
&lt;li&gt;A read marked &lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt; is a stored read that guards nothing, on purpose.&lt;/li&gt;
&lt;li&gt;A projection definition changed by another process isn’t detected until this client registers it again.&lt;/li&gt;
&lt;li&gt;A writer that decides without a guard can still break the rule. If another command appends &lt;code dir=&quot;auto&quot;&gt;BookBorrowed&lt;/code&gt; with read protection &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;, the protected command detects that event. The unprotected command’s own decision is still unguarded: if it reads first and commits last, it lends a copy that isn’t there.&lt;/li&gt;
&lt;li&gt;Uniqueness across keys is a constraint, not this. Two members registering the same email are two different keys, and no read of one key can see the other.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, Arc also refuses reads it can’t guard instead of running them unguarded: &lt;code dir=&quot;auto&quot;&gt;IReadModels&lt;/code&gt;, raw event-log reads, an &lt;code dir=&quot;auto&quot;&gt;IMongoCollection&amp;#x3C;T&gt;&lt;/code&gt; of a Chronicle-backed model, immediate appends through &lt;code dir=&quot;auto&quot;&gt;IEventLog.Append&lt;/code&gt;, and read models with joins, children or keys taken from an event property. So under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; every read Arc can see is guarded, marked advisory or refused. That’s also why turning it on in an application that already runs is a project of its own.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;what-it-costs&quot;&gt;What it costs&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;A guarded read is a fresh fold of the key’s history every time. Chronicle doesn’t use the materialized state, because that can lag and has no position, and nothing caches the result between commands. Each read makes two tail reads and a fold of the key’s events of the model’s types, and the read makes up to three attempts at the fold if events arrive during it. The first read of a model type in a process also checks the projection definition. Identical reads inside one command share one fold.&lt;/p&gt;
&lt;p&gt;In the kernel, those folds go through one projection per model type, shared by every key of that type and every tenant, so heavy use of one model type queues across keys. No benchmark for read protection is published, and the &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/#costs&quot;&gt;costs section&lt;/a&gt; of Arc’s docs gives the shape of the cost without figures. Keep guarded models flat and keys short-lived: a key per book, order, booking or period rather than one for the life of the library.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;where-to-start&quot;&gt;Where to start&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;For new code, set &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; in the project and put each “may this proceed” rule in a validator that takes the read model. For an application that already runs, I wouldn’t flip it blind. &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; runs every command as before and reports what &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; would guard, refuse or reject. Part 6 is about that path.&lt;/p&gt;
&lt;p&gt;The next part takes the same command to two entities: a member may hold three loans and a book has one copy left, with two read models in one validator and one atomic append.&lt;/p&gt;
&lt;aside aria-label=&quot;What to do when&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;What to do when&lt;/p&gt;&lt;div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A rule depends on stored state of one entity&lt;/strong&gt; (stock, status, a count): set &lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;CratisReadProtection&gt;On&amp;#x3C;/CratisReadProtection&gt;&lt;/code&gt; and take the read model as a &lt;code dir=&quot;auto&quot;&gt;CommandValidator&amp;#x3C;T&gt;&lt;/code&gt; constructor parameter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You only want a hint on screen:&lt;/strong&gt; a query, or &lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt; on the read. It guards nothing (Parts 5 and 7).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The rule is uniqueness:&lt;/strong&gt; a Chronicle &lt;a href=&quot;https://www.cratis.io/chronicle/constraints/&quot;&gt;constraint&lt;/a&gt;, not a guarded read (Part 7).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Your application already runs with plain reads:&lt;/strong&gt; &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; first, then &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; (Part 6).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A command comes back with &lt;code dir=&quot;auto&quot;&gt;concurrencyViolation&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt;:&lt;/strong&gt; read again and let the caller decide whether to submit again.&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;The full walkthrough is Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/getting-started/&quot;&gt;Getting started with read protection&lt;/a&gt;, and &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/validators/&quot;&gt;Validators and read protection&lt;/a&gt; covers what a validator may take. &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/how-it-works/&quot;&gt;How read protection works&lt;/a&gt; explains how guards are derived and merged, and &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/&quot;&gt;Choosing how a command’s rule holds&lt;/a&gt; compares read protection with constraints, aggregates, stream decisions and explicit scopes.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Read protection as described here needs Arc 22.108.0 or later and Chronicle 19.68.0 or later.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;Previous: &lt;a href=&quot;https://blog.cratis.io/the-bug-you-never-see/&quot;&gt;Part 01 — The bug you never see&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>arc</category><category>chronicle</category><category>concurrency</category><category>event-sourcing</category><category>validation</category></item><item><title>The bug you never see · Decisions that hold, Part 1</title><link>https://blog.cratis.io/the-bug-you-never-see/</link><guid isPermaLink="true">https://blog.cratis.io/the-bug-you-never-see/</guid><description>Is there stock? Is the name free? Is the balance enough? Every check-then-act decision has a gap between the check and the write, and two requests can both pass it. Nothing throws, the tests are green, and the bad state turns up weeks later. Why that is, what the database defaults do and don&apos;t do, and how to spot it in your own code.</description><pubDate>Tue, 20 Oct 2026 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://blog.cratis.io/the-bug-you-never-see/&quot;&gt;Decisions that hold&lt;/a&gt; · Part 01 of 11&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Is there a copy left? Is this user name free? Is the balance enough for the withdrawal? Is the 10:30 slot still open? Has this customer already used the welcome discount?&lt;/p&gt;
&lt;p&gt;Most applications are full of questions like these, and each one is half of a decision. The code reads something, checks it, and then writes. Between the read and the write there is a gap, and in most code nothing connects the write to what the read saw. Two requests can both read “yes”, both pass the check, and both write.&lt;/p&gt;
&lt;p&gt;This series is about making those decisions hold. This first part is about the problem itself, because in my experience it’s one of the most common bugs in business software and one of the least discussed. It doesn’t throw and it doesn’t show up in tests. When it does surface, it rarely looks like a bug.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;two-requests-for-the-last-copy&quot;&gt;Two requests for the last copy&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Here is the code most of us have written, in some form, many times. An order is accepted only while there is stock:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Microsoft&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EntityFrameworkCore&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Product&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Stock &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Order&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; ProductId &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Quantity &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ShopContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;DbContextOptions&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;ShopContext&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; options&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;DbContext&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;options&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;DbSet&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Product&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; Products &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Set&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Product&lt;/span&gt;&lt;span&gt;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;DbSet&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Order&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; Orders &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Set&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Order&lt;/span&gt;&lt;span&gt;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PlaceOrder&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ShopContext&lt;/span&gt;&lt;span&gt;&lt;span&gt; db&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;bool&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; productId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; quantity&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; product &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;db&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Products&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;SingleAsync&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;p &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;productId&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;product&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Stock&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;product&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Stock&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;db&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Orders&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Add&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Order&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ProductId&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;productId&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Quantity&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;db&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;SaveChangesAsync&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;It reads well, and every test of it passes. Now take a product with one item left and two customers who press &lt;strong&gt;Buy&lt;/strong&gt; within a few milliseconds of each other:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;request A                                   request B&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;SELECT product 7: Stock = 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                                            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;SELECT product 7: Stock = 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;1 &gt;= 1, set Stock = 0, add an order&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;SaveChanges: UPDATE Stock = 0, INSERT order&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                                            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;1 &gt;= 1, set Stock = 0, add an order&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                                            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;SaveChanges: UPDATE Stock = 0, INSERT order&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Products: Stock = 0      Orders: two rows for product 7&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/two-requests-one-copy.Tw_DfeMF_Z1D1QOA.webp&quot; alt=&quot;Two request lanes against one Products row with Stock 1. Both lanes read Stock 1, both pass the check, and both save. The row ends at Stock 0 and the Orders table has two rows for one item.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2400&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Both checks were right when they ran. The row says 0, and two orders exist for one item.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Both requests succeed. EF Core sends the new value of the property, so both updates write &lt;code dir=&quot;auto&quot;&gt;Stock = 0&lt;/code&gt;, and the second one overwrites the first. The stock column looks exactly right. The only trace is a second order for an item that was never there, and it appears as a successful request in every log.&lt;/p&gt;
&lt;p&gt;That’s the classic lost update. Microsoft’s &lt;a href=&quot;https://learn.microsoft.com/en-us/sql/relational-databases/sql-server-transaction-locking-and-row-versioning-guide&quot;&gt;locking and row versioning guide&lt;/a&gt; defines it in one sentence: lost updates “occur when two or more transactions select the same row and then update the row based on the value originally selected.”&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;why-you-never-see-it&quot;&gt;Why you never see it&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The gap is small, often a few milliseconds, and almost everything about how we build and test software keeps two requests out of it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tests run one request at a time.&lt;/strong&gt; A test of &lt;code dir=&quot;auto&quot;&gt;PlaceOrder&lt;/code&gt; calls it, checks the result, and stops. A second call that starts after the first has finished reads the new stock and is correctly rejected.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Development has one user.&lt;/strong&gt; You can’t double-book a slot you’re the only person looking at.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It doesn’t need two users.&lt;/strong&gt; A double-clicked button, an HTTP client that retries after a timeout, a load balancer that resends, a message delivered twice: each of these is two requests carrying the same intent, and they arrive close together by construction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nothing fails.&lt;/strong&gt; No exception, no error log, no alert. Every request returned success.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The result looks like bad data.&lt;/strong&gt; A negative balance, a member with four loans when the limit is three, two bookings for one room. Someone fixes the row by hand, and nobody connects it to the code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It surfaces late.&lt;/strong&gt; Support hears about it from a customer, or finance finds it in a reconciliation weeks later, long after the logs that would explain it have rotated.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So the bug survives code review, testing and staging, and shows up in production, most often under load on the busiest day or when a retry lands in the gap, where it’s hardest to reproduce.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;doesnt-the-database-handle-this&quot;&gt;Doesn’t the database handle this?&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;It’s a reasonable assumption, and it’s mostly wrong for the default settings.&lt;/p&gt;
&lt;p&gt;First, look at where the transaction is. In the code above, EF Core runs &lt;code dir=&quot;auto&quot;&gt;SingleAsync&lt;/code&gt; as its own statement. &lt;a href=&quot;https://learn.microsoft.com/en-us/ef/core/saving/transactions&quot;&gt;By default&lt;/a&gt;, “all changes in a single call to &lt;code dir=&quot;auto&quot;&gt;SaveChanges&lt;/code&gt; are applied in a transaction”, and that transaction begins after the read. The read and the write are in different transactions, so no isolation level on the write can protect a value read before it began.&lt;/p&gt;
&lt;p&gt;Second, even with one transaction around both, the default isolation levels don’t stop this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PostgreSQL: “&lt;a href=&quot;https://www.postgresql.org/docs/current/transaction-iso.html#XACT-READ-COMMITTED&quot;&gt;Read Committed&lt;/a&gt; is the default isolation level”.&lt;/li&gt;
&lt;li&gt;SQL Server: &lt;a href=&quot;https://learn.microsoft.com/en-us/sql/t-sql/statements/set-transaction-isolation-level-transact-sql&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;READ COMMITTED&lt;/code&gt;&lt;/a&gt; “is the SQL Server default”, and under it “data can be changed by other transactions between individual statements within the current transaction”. Azure SQL Database turns on &lt;code dir=&quot;auto&quot;&gt;READ_COMMITTED_SNAPSHOT&lt;/code&gt; by default, which changes how reads are served, not this.&lt;/li&gt;
&lt;li&gt;MySQL: &lt;a href=&quot;https://dev.mysql.com/doc/refman/8.4/en/innodb-transaction-isolation-levels.html&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;REPEATABLE READ&lt;/code&gt;&lt;/a&gt; “is the default isolation level for InnoDB”.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here is what each does when both requests run the read and the update inside one transaction, and the new stock is computed in application code:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Isolation level&lt;/th&gt;
&lt;th&gt;What the second request’s &lt;code dir=&quot;auto&quot;&gt;UPDATE&lt;/code&gt; does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PostgreSQL &lt;code dir=&quot;auto&quot;&gt;READ COMMITTED&lt;/code&gt; (default)&lt;/td&gt;
&lt;td&gt;Waits for the first transaction to commit, then writes its own value over it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQL Server &lt;code dir=&quot;auto&quot;&gt;READ COMMITTED&lt;/code&gt; (default)&lt;/td&gt;
&lt;td&gt;The same&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MySQL InnoDB &lt;code dir=&quot;auto&quot;&gt;REPEATABLE READ&lt;/code&gt; (default)&lt;/td&gt;
&lt;td&gt;The same. The &lt;code dir=&quot;auto&quot;&gt;SELECT&lt;/code&gt; reads a snapshot, but the &lt;code dir=&quot;auto&quot;&gt;UPDATE&lt;/code&gt; works on the latest row&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PostgreSQL &lt;code dir=&quot;auto&quot;&gt;REPEATABLE READ&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;SERIALIZABLE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fails with “could not serialize access due to concurrent update”, and the application has to retry the transaction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQL Server &lt;code dir=&quot;auto&quot;&gt;SNAPSHOT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fails with error 3960, “Snapshot isolation transaction aborted due to update conflict”, and the application has to retry&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The MySQL row surprises people, because “repeatable read” sounds like protection. The &lt;a href=&quot;https://dev.mysql.com/doc/refman/8.4/en/innodb-consistent-read.html&quot;&gt;manual&lt;/a&gt; is explicit that “the snapshot of the database state applies to &lt;code dir=&quot;auto&quot;&gt;SELECT&lt;/code&gt; statements within a transaction, not necessarily to DML statements”, and its &lt;a href=&quot;https://dev.mysql.com/doc/refman/8.4/en/innodb-locking-reads.html&quot;&gt;locking reads page&lt;/a&gt; opens with the exact case: “If you query data and then insert or update related data within the same transaction, the regular &lt;code dir=&quot;auto&quot;&gt;SELECT&lt;/code&gt; statement does not give enough protection.”&lt;/p&gt;
&lt;p&gt;So the stronger levels do catch this lost update, as an error you have to handle. They catch it because both requests update the same row. Many rules don’t work that way.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-rule-nobody-writes-to&quot;&gt;The rule nobody writes to&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Say a library member may hold at most three loans. The check counts rows and the act inserts one:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;-- Both requests run this for member 42, who has two active loans.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;BEGIN&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;count&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; loans &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; member_id &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;42&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AND&lt;/span&gt;&lt;span&gt; returned_at &lt;/span&gt;&lt;span&gt;IS&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;;  &lt;/span&gt;&lt;span&gt;-- 2, so below 3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;INSERT INTO&lt;/span&gt;&lt;span&gt; loans (member_id, book_id) &lt;/span&gt;&lt;span&gt;VALUES&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;42&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1001&lt;/span&gt;&lt;span&gt;);                 &lt;/span&gt;&lt;span&gt;-- the other request inserts 1002&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;COMMIT&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Both requests see two loans, both insert, and the member now holds four. Neither transaction updated a row the other one touched, so there is no update conflict to detect and no unique key to collide. This is &lt;strong&gt;write skew&lt;/strong&gt;: each transaction decides from data the other one is changing. The &lt;a href=&quot;https://wiki.postgresql.org/wiki/SSI&quot;&gt;PostgreSQL wiki&lt;/a&gt; defines it as two concurrent transactions that “each determine what they are writing based on reading a data set which overlaps what the other is writing”.&lt;/p&gt;
&lt;p&gt;Snapshot isolation allows it. PostgreSQL’s &lt;code dir=&quot;auto&quot;&gt;REPEATABLE READ&lt;/code&gt; is implemented as snapshot isolation, and its &lt;a href=&quot;https://www.postgresql.org/docs/current/transaction-iso.html#XACT-SERIALIZABLE&quot;&gt;documentation&lt;/a&gt; shows the same shape with two sums and two inserts, where “if either transaction were running at the Repeatable Read isolation level, both would be allowed to commit.” Its &lt;a href=&quot;https://www.postgresql.org/docs/current/transaction-iso.html#XACT-REPEATABLE-READ&quot;&gt;Repeatable Read section&lt;/a&gt; also says plainly that “attempts to enforce business rules by transactions running at this isolation level are not likely to work correctly without careful use of explicit locks.” SQL Server’s &lt;code dir=&quot;auto&quot;&gt;SNAPSHOT&lt;/code&gt; &lt;a href=&quot;https://learn.microsoft.com/en-us/sql/relational-databases/sql-server-transaction-locking-and-row-versioning-guide&quot;&gt;checks for conflicts&lt;/a&gt; on the rows a transaction modifies, and the two loan inserts modify different rows, so both commit there as well.&lt;/p&gt;
&lt;p&gt;Write skew is the general shape of most check-then-act rules: a limit counted over rows, an overlap between bookings, “at least one person on call”, “only one active subscription”, “no more than 5000 withdrawn this month”. The check reads a set and the act adds to it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/where-the-check-and-the-act-separate.CGHlv3k0_1krTrE.webp&quot; alt=&quot;Three stages of one request: read, decide, write. A marked gap between read and write is labeled “anything can land here”. Below, three rows show where that gap sits: an ORM read and SaveChanges in separate transactions, a single transaction at the default isolation level, and a command that checks a read model before appending events.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2400&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The check and the act are separate moments. Every fix is a way of tying the second to what the first saw.&lt;/em&gt;&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-usual-fixes-and-where-each-stops&quot;&gt;The usual fixes, and where each stops&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;There are good tools for this in a relational database. Each one covers a particular shape of rule.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A unique constraint&lt;/strong&gt; makes uniqueness hold for every writer. In PostgreSQL’s words, &lt;a href=&quot;https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-UNIQUE-CONSTRAINTS&quot;&gt;unique constraints&lt;/a&gt; “ensure that the data contained in a column, or a group of columns, is unique among all the rows in the table.” It is the right answer for “is the name free?”, and the &lt;code dir=&quot;auto&quot;&gt;SELECT&lt;/code&gt;-then-&lt;code dir=&quot;auto&quot;&gt;INSERT&lt;/code&gt; check in front of it becomes a friendly message, not the rule. It can’t count or sum. PostgreSQL’s &lt;a href=&quot;https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-EXCLUSION&quot;&gt;exclusion constraints&lt;/a&gt; extend the idea to overlaps such as bookings, but not to “at most three”.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A conditional write&lt;/strong&gt; moves the check into the statement that acts:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Microsoft&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EntityFrameworkCore&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PlaceOrderConditionally&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ShopContext&lt;/span&gt;&lt;span&gt;&lt;span&gt; db&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;bool&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; productId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; quantity&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; transaction &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;db&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Database&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BeginTransactionAsync&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; reserved &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;db&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Products&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Where&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;p &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;productId&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Stock&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ExecuteUpdateAsync&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;s &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;SetProperty&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;p &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Stock&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; p &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Stock&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;reserved&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;db&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Orders&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Add&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Order&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ProductId&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;productId&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Quantity&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;db&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;SaveChangesAsync&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;transaction&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;CommitAsync&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;That is &lt;code dir=&quot;auto&quot;&gt;UPDATE products SET stock = stock - @quantity WHERE id = @id AND stock &gt;= @quantity&lt;/code&gt;, and &lt;code dir=&quot;auto&quot;&gt;ExecuteUpdateAsync&lt;/code&gt; &lt;a href=&quot;https://learn.microsoft.com/en-us/ef/core/saving/execute-insert-update-delete#concurrency-control-and-rows-affected&quot;&gt;returns the number of rows affected&lt;/a&gt;. Under PostgreSQL’s &lt;code dir=&quot;auto&quot;&gt;READ COMMITTED&lt;/code&gt;, a second update that waited for the first sees the new row, and “the search condition of the command (the &lt;code dir=&quot;auto&quot;&gt;WHERE&lt;/code&gt; clause) is re-evaluated”, so it matches nothing. It works as long as the whole rule fits in the &lt;code dir=&quot;auto&quot;&gt;WHERE&lt;/code&gt; clause of one row. Under &lt;code dir=&quot;auto&quot;&gt;REPEATABLE READ&lt;/code&gt; the same statement fails with a serialization error and you retry.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A concurrency token&lt;/strong&gt; is EF Core’s &lt;a href=&quot;https://learn.microsoft.com/en-us/ef/core/saving/concurrency&quot;&gt;optimistic concurrency&lt;/a&gt;. Mark a property with &lt;code dir=&quot;auto&quot;&gt;[ConcurrencyCheck]&lt;/code&gt;, or map a SQL Server &lt;code dir=&quot;auto&quot;&gt;rowversion&lt;/code&gt; with &lt;code dir=&quot;auto&quot;&gt;[Timestamp]&lt;/code&gt;, and EF Core adds its original value to the &lt;code dir=&quot;auto&quot;&gt;WHERE&lt;/code&gt; clause of the update, so the update “only modifies the row if the &lt;code dir=&quot;auto&quot;&gt;Version&lt;/code&gt; column hasn’t changed since the moment we queried it.” A conflict throws &lt;code dir=&quot;auto&quot;&gt;DbUpdateConcurrencyException&lt;/code&gt;, and resolving it, including any retry, is your code. It fixes the lost update in &lt;code dir=&quot;auto&quot;&gt;PlaceOrder&lt;/code&gt;. It covers only rows you update or delete: the docs note the exception “is generally never thrown when adding entities”, so a token on the rows you insert does nothing for the loan count. A version on the parent row does work, if every writer that adds a loan also bumps the member’s version: two concurrent inserts then both update the member row, and the second one gets the exception. It’s the optimistic form of the parent-row lock below, with the same every-writer condition.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A locking read&lt;/strong&gt;, &lt;code dir=&quot;auto&quot;&gt;SELECT ... FOR UPDATE&lt;/code&gt;, holds the rows it returns until the transaction ends. In &lt;a href=&quot;https://www.postgresql.org/docs/current/explicit-locking.html#LOCKING-ROWS&quot;&gt;PostgreSQL&lt;/a&gt; it “causes the rows retrieved by the &lt;code dir=&quot;auto&quot;&gt;SELECT&lt;/code&gt; statement to be locked as though for update.” A row that doesn’t exist yet isn’t returned, so it isn’t locked. MySQL’s &lt;code dir=&quot;auto&quot;&gt;REPEATABLE READ&lt;/code&gt; adds gap locks over the index range a locking read scans, which do block inserts into it, and PostgreSQL doesn’t. The common pattern for a rule over many rows is to lock a parent row, the member, as a mutex. That holds only while every code path that can break the rule takes the same lock first and checks the rule after it, and it costs waiting and the occasional deadlock. Under PostgreSQL’s &lt;code dir=&quot;auto&quot;&gt;REPEATABLE READ&lt;/code&gt; even that isn’t enough: the snapshot is fixed when the transaction’s first query starts, and the &lt;a href=&quot;https://www.postgresql.org/docs/current/applevel-consistency.html&quot;&gt;docs&lt;/a&gt; warn that “if the snapshot seen by the transaction predates obtaining the lock, it might predate some now-committed changes in the table”. The count after the lock can still miss the other request’s loan, so take the lock at &lt;code dir=&quot;auto&quot;&gt;READ COMMITTED&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Serializable transactions&lt;/strong&gt; handle write skew in PostgreSQL. Its &lt;code dir=&quot;auto&quot;&gt;SERIALIZABLE&lt;/code&gt; level monitors read/write dependencies and rolls one transaction back with SQLSTATE &lt;code dir=&quot;auto&quot;&gt;40001&lt;/code&gt;. The &lt;a href=&quot;https://www.postgresql.org/docs/current/applevel-consistency.html&quot;&gt;docs&lt;/a&gt; set the conditions: it works “if the Serializable transaction isolation level is used for all writes and for all reads which need a consistent view of the data”, and the application needs a framework that retries transactions rolled back with a serialization failure. SQL Server and MySQL implement &lt;code dir=&quot;auto&quot;&gt;SERIALIZABLE&lt;/code&gt; with locks, so the same pattern tends to block or deadlock instead, and the losing transaction still has to be retried.&lt;/p&gt;
&lt;p&gt;Put together: a constraint when the rule is uniqueness or exclusion, a conditional write when the rule fits in one row, a token when the danger is overwriting a row someone else changed. For rules that span rows or tables, and rules over history (“three in any 30 days”, “5000 per month”), you’re left with locks, a version on a parent row, or serializable transactions, and all of them depend on every writer following the same protocol. None of them is the default, and none of them is visible in the &lt;code dir=&quot;auto&quot;&gt;PlaceOrder&lt;/code&gt; code above.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;event-sourcing-doesnt-make-it-go-away&quot;&gt;Event sourcing doesn’t make it go away&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;You might expect event sourcing and CQRS to sidestep this. They make it more common.&lt;/p&gt;
&lt;p&gt;In many CQRS codebases, including the Arc style this series uses, the side that decides asks a read model: a projection built from the events. Read models are built after the fact. Chronicle’s &lt;a href=&quot;https://www.cratis.io/chronicle/projections/eventual-consistency/&quot;&gt;documentation&lt;/a&gt; says it directly: “read models are updated asynchronously as events are processed”, and the append returns before the projection has run. So a command that checks a read model and then appends has the same gap as &lt;code dir=&quot;auto&quot;&gt;PlaceOrder&lt;/code&gt;, plus the projection’s lag. Two requests don’t even have to overlap. A request that arrives after the first one has completed can still read the old stock and be approved.&lt;/p&gt;
&lt;p&gt;Folding the state fresh from the events doesn’t close it either. A fresh read is a correct snapshot of the moment it was taken, and an append that follows it is not conditioned on it. A stream’s expected version helps when the rule lives entirely in the one stream you append to. It says nothing about a read model built from other events, or about a second entity the rule depends on.&lt;/p&gt;
&lt;p&gt;Arc is no exception. With read protection Off, &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/&quot;&gt;which is the default&lt;/a&gt;, “an injected read model is a plain read, it returns a snapshot, and it guards nothing.” The next part starts from exactly that command.&lt;/p&gt;
&lt;p&gt;What event sourcing does give you is a way to say what the decision depended on. An event log is ordered, and every event has a position. A decision can note the position before it reads, fold the events it needs, and append with a condition: only if no event that would have changed what I read has arrived since. That’s not a lock. Nothing waits, and a conflict is an answer: the state changed, read again and decide again. The condition can be as narrow as the rule: the event types that build this read model, for this key. The rest of the series is about that condition, how to get one, and where it stops.&lt;/p&gt;
&lt;aside aria-label=&quot;How to spot it in your own code&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;How to spot it in your own code&lt;/p&gt;&lt;div&gt;&lt;p&gt;Look for any rule that reads state before it writes:&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;A query followed by &lt;code dir=&quot;auto&quot;&gt;SaveChanges&lt;/code&gt; in the same handler: &lt;code dir=&quot;auto&quot;&gt;SingleAsync&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;FirstOrDefaultAsync&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;AnyAsync&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;CountAsync&lt;/code&gt;, then &lt;code dir=&quot;auto&quot;&gt;Add&lt;/code&gt; or a property change.&lt;/li&gt;
&lt;li&gt;A value computed in application code from a value you read: &lt;code dir=&quot;auto&quot;&gt;product.Stock -= quantity&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;account.Balance -= amount&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;if (!await db.Users.AnyAsync(u =&gt; u.Email == email))&lt;/code&gt; followed by an insert.&lt;/li&gt;
&lt;li&gt;Words in the requirement such as “at most”, “no more than”, “only one”, “once”, “per month”, “still available”.&lt;/li&gt;
&lt;li&gt;A validator, cache, search index or read model consulted before a command writes.&lt;/li&gt;
&lt;li&gt;Anything that can arrive twice: a submit button, a client retry, a redelivered message.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;For each one, ask what happens if two of them run at the same moment, and what ties the write to what the check read:&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;Uniqueness → a unique constraint or index; the check in front is only the message.&lt;/li&gt;
&lt;li&gt;One row’s state → a conditional &lt;code dir=&quot;auto&quot;&gt;UPDATE ... WHERE&lt;/code&gt; and a rows-affected check, or a concurrency token.&lt;/li&gt;
&lt;li&gt;Many rows or tables → a lock every writer takes before it checks (at &lt;code dir=&quot;auto&quot;&gt;READ COMMITTED&lt;/code&gt; in PostgreSQL), a version on a parent row every writer bumps, or serializable transactions with retries.&lt;/li&gt;
&lt;li&gt;A read model before an append → the append needs a condition on what was read; Part 2 covers how Arc and Chronicle express one, and where it stops.&lt;/li&gt;
&lt;li&gt;Nothing ties them → you have the bug. It just hasn’t been reported yet.&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;div&gt;&lt;h2 id=&quot;the-series&quot;&gt;The series&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Decisions that hold&lt;/em&gt; is eleven posts on making a decision still true at the moment it’s written, mostly in Arc and Chronicle, with the limits of each mechanism stated where it applies.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.cratis.io/the-bug-you-never-see/&quot;&gt;The bug you never see&lt;/a&gt;. Check-then-act decisions, why two requests can both pass the check, and what the database defaults do about it.&lt;/li&gt;
&lt;li&gt;The read model said yes. A command that checks a read model and then appends, and what it takes in Arc and Chronicle for that check to still hold at the append.&lt;/li&gt;
&lt;li&gt;One rule, two entities, one append. A rule over a member and a book: two reads, one fact for each entity, and one atomic append.&lt;/li&gt;
&lt;li&gt;A limit for one account and one month. Guarding a decision on one stream, so last month’s activity doesn’t conflict with today’s.&lt;/li&gt;
&lt;li&gt;When Arc says no. The two kinds of refusal, what each means, and what the caller and the UI should do.&lt;/li&gt;
&lt;li&gt;Turning read protection on in an application that already runs. Measuring first, fixing what it finds, and switching on per project.&lt;/li&gt;
&lt;li&gt;Not every rule needs a guarded read. Constraints, aggregates, explicit scopes, stream decisions, repair and hints, and the choices that fail silently.&lt;/li&gt;
&lt;li&gt;The same guard without Arc: decision reads and append conditions. The Chronicle calls underneath, and how they map to the dynamic consistency boundary.&lt;/li&gt;
&lt;li&gt;Testing a decision against a race. Putting a competing write between a command’s read and its commit.&lt;/li&gt;
&lt;li&gt;How a guard is built, merged and widened. Predicting exactly which events make a command fail.&lt;/li&gt;
&lt;li&gt;Decisions that hold: questions and a decision guide. One page to come back to.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you’ve read &lt;em&gt;Cratis: from script to stage&lt;/em&gt;, its parts on &lt;a href=&quot;https://blog.cratis.io/rules-that-hold-when-you-write/&quot;&gt;rules that hold when you write&lt;/a&gt; and &lt;a href=&quot;https://blog.cratis.io/validation-all-the-way-down/&quot;&gt;validation all the way down&lt;/a&gt; covered constraints, concurrency scopes and validators. This series goes further into the decisions that read state first.&lt;/p&gt;
&lt;p&gt;Next is Part 2, &lt;em&gt;The read model said yes&lt;/em&gt;: the same last-copy race as a library command in Arc, and what changes, and what doesn’t, when the read it checks is tied to the append.&lt;/p&gt;</content:encoded><category>concurrency</category><category>event-sourcing</category><category>cqrs</category><category>postgresql</category><category>sql-server</category></item><item><title>Where does each tenant&apos;s data live? Storage connection resolution in Chronicle and Arc</title><link>https://blog.cratis.io/storage-connection-resolution/</link><guid isPermaLink="true">https://blog.cratis.io/storage-connection-resolution/</guid><description>Chronicle and Arc used to derive database names and connect with one credential. Now they can ask. This post shows how the question and the answer work, and wires one example through a Chronicle kernel, an Arc application and a plain client with no Arc in it.</description><pubDate>Sat, 17 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;div&gt;&lt;h2 id=&quot;tldr&quot;&gt;TL;DR&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Until now, Chronicle and Arc decided for themselves where a tenant’s data lives. Chronicle derived a database name for every event store and namespace and connected with one credential. Arc’s MongoDB integration appended the tenant to a database name, and Entity Framework Core used the same connection for everyone. That’s fine until your platform has opinions: a server per region, a database per customer, a login that can see one tenant and nothing else.&lt;/p&gt;
&lt;p&gt;Connection resolution lets them ask instead. When a connection is needed, the caller describes what it’s for, and a resolver answers with the parts it decides. Anything it leaves out stays as configured. Nothing changes until you configure it.&lt;/p&gt;
&lt;p&gt;This post explains how that works, and then builds one example you can run: a Chronicle kernel that places each namespace by a naming rule, an Arc application that asks an HTTP endpoint for each tenant’s database and login, and a small client with no Arc in it that asks the same endpoint. Arc is a convenience here, not a requirement.&lt;/p&gt;
&lt;p&gt;The example uses .NET 10, Chronicle 19.77.2, Arc 22.112.0, MongoDB 8.2 and MongoDB.Driver 3.12.0. Connection resolution needs Chronicle 19.74.2 or later and Arc 22.109.0 or later.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-question-and-the-answer&quot;&gt;The question and the answer&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;img alt=&quot;A diagram titled Ask, don’t derive. Four steps. One: a connection is needed. Two: the caller describes it, what it is for. Three: a resolver answers, only what it knows. Four: the connection opens, the rest is kept. A note reads: Nothing changes until you configure it.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1700&quot; src=&quot;https://blog.cratis.io/_astro/ask-dont-derive.DzJ9Dc98_2ajKpD.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The caller says what it needs the connection for. The resolver says what it knows.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The caller describes the connection with a few fields. Arc sends three: the &lt;code dir=&quot;auto&quot;&gt;storage&lt;/code&gt; (&lt;code dir=&quot;auto&quot;&gt;MongoDB&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;SqlServer&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;PostgreSql&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;Sqlite&lt;/code&gt;), the &lt;code dir=&quot;auto&quot;&gt;purpose&lt;/code&gt; (&lt;code dir=&quot;auto&quot;&gt;Runtime&lt;/code&gt; for reading and writing, &lt;code dir=&quot;auto&quot;&gt;Schema&lt;/code&gt; for migrations and creating tables) and a &lt;code dir=&quot;auto&quot;&gt;scope&lt;/code&gt;, which for Arc holds the &lt;code dir=&quot;auto&quot;&gt;tenant&lt;/code&gt;. Chronicle sends the same &lt;code dir=&quot;auto&quot;&gt;storage&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;purpose&lt;/code&gt;, and a scope that says which database it’s about: the &lt;code dir=&quot;auto&quot;&gt;cluster&lt;/code&gt;, an &lt;code dir=&quot;auto&quot;&gt;eventStore&lt;/code&gt;, a &lt;code dir=&quot;auto&quot;&gt;namespace&lt;/code&gt; (its events) or &lt;code dir=&quot;auto&quot;&gt;readModels&lt;/code&gt; (its projected read models), with the event store and namespace names.&lt;/p&gt;
&lt;p&gt;The resolver answers with any of these, and every part is optional:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Part&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;connectionString&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Replaces the configured connection string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;database&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The database to use&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;schema&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The schema, for storage that has one&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;identity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;userName&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;password&lt;/code&gt;, or an &lt;code dir=&quot;auto&quot;&gt;accessToken&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;expiresAt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;When to ask again&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Arc and Chronicle share this model, and it has two slots: &lt;code dir=&quot;auto&quot;&gt;Connection&lt;/code&gt; decides where to connect and &lt;code dir=&quot;auto&quot;&gt;Identity&lt;/code&gt; decides who connects. They apply what’s configured, then what the &lt;code dir=&quot;auto&quot;&gt;Connection&lt;/code&gt; slot resolved, then what the &lt;code dir=&quot;auto&quot;&gt;Identity&lt;/code&gt; slot resolved, and a later part wins. That’s how the common split becomes a configuration choice. Keep the server in configuration and fetch only the credential, or the other way around.&lt;/p&gt;
&lt;p&gt;Each slot takes one of four resolvers: &lt;code dir=&quot;auto&quot;&gt;Default&lt;/code&gt; leaves things alone, &lt;code dir=&quot;auto&quot;&gt;Template&lt;/code&gt; fills in a naming rule such as &lt;code dir=&quot;auto&quot;&gt;tenant-{tenant}&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;Http&lt;/code&gt; calls an endpoint you write, and &lt;code dir=&quot;auto&quot;&gt;Custom&lt;/code&gt; is your own code behind &lt;code dir=&quot;auto&quot;&gt;IConnectionResolver&lt;/code&gt;. The &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/tenancy/connection-resolution/&quot;&gt;Arc docs&lt;/a&gt; cover them all, and Chronicle’s &lt;a href=&quot;https://www.cratis.io/chronicle/hosting/configuration/storage-connection-resolution/&quot;&gt;storage connection resolution&lt;/a&gt; page covers what the kernel asks and answers, including SQL storage and schemas.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-contract-is-plain-rest&quot;&gt;The contract is plain REST&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code dir=&quot;auto&quot;&gt;Http&lt;/code&gt; resolver posts to one endpoint, and that endpoint can be written in anything. This is the request Arc sends for a tenant:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;POST&lt;/span&gt;&lt;span&gt; /connections&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Content-Type&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;application/json; charset=utf-8&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;X-Api-Key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;dev-only-key&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;storage&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;MongoDB&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;purpose&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Runtime&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;scope&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;tenant&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;acme&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This is an answer that places a tenant in its own database with its own login:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;database&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;acme-arc&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;identity&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;userName&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;acme&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;acme-pw&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;},&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;expiresAt&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;2026-10-17T07:05:51+00:00&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;204 No Content&lt;/code&gt; means “keep the configured connection”, and any other status except &lt;code dir=&quot;auto&quot;&gt;200&lt;/code&gt; fails the connection. That’s the whole &lt;a href=&quot;https://www.cratis.io/arc/connection-resolution-contract/&quot;&gt;connection resolution contract&lt;/a&gt;, which also covers caching and security and ships an OpenAPI description. Because the contract doesn’t mention Arc, it’s the seam for the last part of this post.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-example&quot;&gt;The example&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;You’ll run four things: MongoDB and a Chronicle kernel in Docker, a small endpoint that knows your tenants, an Arc application, and a plain client. Two tenants, &lt;code dir=&quot;auto&quot;&gt;acme&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;globex&lt;/code&gt;, and one that nobody told the endpoint about, &lt;code dir=&quot;auto&quot;&gt;initech&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;the-infrastructure&quot;&gt;The infrastructure&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;MongoDB has to be a replica set because Chronicle appends in transactions, and a replica set with authentication needs a key file:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;openssl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;rand&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-base64&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;756&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;keyfile&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The init script creates one login per tenant. It only allows that tenant into its own &lt;code dir=&quot;auto&quot;&gt;-arc&lt;/code&gt; database, which is where the Arc application will keep its data:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;admin&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;db&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getSiblingDB&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;admin&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tenant&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;of&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;acme&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;globex&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;])&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;admin&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;createUser&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;user&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tenant&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;pwd&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;`${&lt;/span&gt;&lt;span&gt;tenant&lt;/span&gt;&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;-pw&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;roles&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;role&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;readWrite&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;db&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;`${&lt;/span&gt;&lt;span&gt;tenant&lt;/span&gt;&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;-arc&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The kernel is configured in the Compose file. The environment variables at the bottom are the whole of Chronicle’s side: a &lt;code dir=&quot;auto&quot;&gt;Template&lt;/code&gt; resolver on the &lt;code dir=&quot;auto&quot;&gt;Connection&lt;/code&gt; slot, with a naming rule for the database. The cluster database stays on &lt;code dir=&quot;auto&quot;&gt;connectionDetails&lt;/code&gt;, as before. The images are pinned by digest, and this is the development image, so it generates its own certificate and OAuth keys. &lt;a href=&quot;https://blog.cratis.io/running-chronicle-in-production/&quot;&gt;Running Chronicle in production&lt;/a&gt; covers what changes for a real deployment.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;services&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;mongo&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;image&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;mongo:8.2@sha256:e0ce8c35124d4a9f9785532d1f268f39e9728ffa1cb38f46fa482436424c4bd3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;bash -c &quot;cp /run/keyfile-src /data/keyfile &amp;#x26;&amp;#x26; chmod 400 /data/keyfile &amp;#x26;&amp;#x26; chown mongodb:mongodb /data/keyfile &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;exec docker-entrypoint.sh mongod --replSet rs0 --bind_ip_all --keyFile /data/keyfile&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;environment&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;MONGO_INITDB_ROOT_USERNAME&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;root&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;MONGO_INITDB_ROOT_PASSWORD&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;rootpw&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;volumes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;./keyfile:/run/keyfile-src:ro&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;./mongo/init-tenants.js:/docker-entrypoint-initdb.d/init-tenants.js:ro&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;ports&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;127.0.0.1:27017:27017&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;healthcheck&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;test&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;CMD&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;mongosh&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;-u&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;root&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;-p&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;rootpw&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;--quiet&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;--eval&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;try { rs.status().ok } catch (e) { rs.initiate({_id:&apos;rs0&apos;,members:[{_id:0,host:&apos;mongo:27017&apos;}]}).ok }&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;interval&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;5s&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;timeout&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;10s&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;retries&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;20&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;image&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;cratis/chronicle:19.77.2-development@sha256:91abcf6bc1eba69b7a3887f3dd800ca2630ca39e79c87bb9c01c765047f0c232&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;depends_on&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;mongo&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;condition&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;service_healthy&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;environment&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;Cratis__Chronicle__Storage__ConnectionDetails&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;mongodb://root:rootpw@mongo:27017/?authSource=admin&amp;#x26;replicaSet=rs0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;Cratis__Chronicle__Storage__ConnectionResolution__Connection__Resolver&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Template&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;Cratis__Chronicle__Storage__ConnectionResolution__Connection__Template__Database&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;{eventStore}-{namespace}-{kind}&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;ports&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;127.0.0.1:35000:35000&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Save the script as &lt;code dir=&quot;auto&quot;&gt;mongo/init-tenants.js&lt;/code&gt;, the Compose file as &lt;code dir=&quot;auto&quot;&gt;compose.yaml&lt;/code&gt;, and start it with &lt;code dir=&quot;auto&quot;&gt;docker compose up -d&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;chronicle-on-its-own&quot;&gt;Chronicle on its own&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;No Arc yet. This console program uses only the Chronicle client. It appends one event to the &lt;code dir=&quot;auto&quot;&gt;orders&lt;/code&gt; event store in each of two namespaces:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;dotnet&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-n&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrdersClient&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrdersClient&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;dotnet&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;add&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;package&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis.Chronicle&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--version&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;19.77.2&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; client &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ChronicleClient&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ChronicleOptions&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;foreach&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; tenant &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;&lt;span&gt;[]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;acme&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;globex&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; store &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;client&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;GetEventStore&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;orders&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;tenant&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;store&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventLog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;NewGuid&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ToString&lt;/span&gt;&lt;span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderPlaced&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;tenant&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;42&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WriteLine&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;$&quot;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;tenant&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&lt;span&gt;: appended&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderPlaced&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Customer&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Total&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Run it, then look in MongoDB. Each namespace’s events are in a database of their own, named by the rule in the Compose file:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;docker&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;compose&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;exec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;mongo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;mongosh&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-u&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;root&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-p&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;rootpw&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--quiet&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--eval&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;print(&quot;acme:&quot;, db.getSiblingDB(&quot;orders-acme-namespace&quot;).getCollection(&quot;event-log&quot;).countDocuments({}));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;print(&quot;globex:&quot;, db.getSiblingDB(&quot;orders-globex-namespace&quot;).getCollection(&quot;event-log&quot;).countDocuments({}))&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;acme: 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;globex: 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The projected read models of each namespace get their own database too, &lt;code dir=&quot;auto&quot;&gt;orders-acme-readModels&lt;/code&gt;, because the rule has &lt;code dir=&quot;auto&quot;&gt;{kind}&lt;/code&gt; in it. Use &lt;code dir=&quot;auto&quot;&gt;{kind}&lt;/code&gt; when a namespace’s events and its read models shouldn’t share one. The rule applies to every database Chronicle asks about, so the &lt;code dir=&quot;auto&quot;&gt;Default&lt;/code&gt; namespace and the event store itself get names from it too, such as &lt;code dir=&quot;auto&quot;&gt;orders-Default-namespace&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;orders--eventStore&lt;/code&gt;, where there’s no namespace to fill in. A template only needs configuration, so it works with the standard image. When a rule can’t express your placement, or a login has to differ per tenant, Chronicle’s storage connection resolution page shows the resolvers that call an endpoint or your own code.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;the-endpoint-that-knows-your-tenants&quot;&gt;The endpoint that knows your tenants&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Now the application side. An application that stores its own data per tenant needs somewhere to ask where that is. This is the endpoint. In a real platform it fronts your tenant directory and a secret store, and here it’s a dictionary:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;dotnet&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;web&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-n&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Directory&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; builder &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WebApplication&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;CreateBuilder&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; app &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Build&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// Your tenant directory. In a real platform this is a service or a database, and the passwords live in a secret store.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; tenants &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Dictionary&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;TenantConnection&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;acme&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;acme-arc&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;acme&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;acme-pw&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;globex&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;globex-arc&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;globex&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;globex-pw&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;MapPost&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;/connections&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;HttpRequest&lt;/span&gt;&lt;span&gt;&lt;span&gt; http&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ConnectionRequest&lt;/span&gt;&lt;span&gt;&lt;span&gt; request&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// The answer holds credentials, so authenticate the caller first.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;http&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Headers&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;X-Api-Key&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;dev-only-key&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Results&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;StatusCode&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;StatusCodes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Status401Unauthorized&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// Resolution chooses a destination, so refuse a tenant you do not know instead of guessing one.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;request&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Scope&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;TryGetValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;tenant&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt;&lt;span&gt; tenant&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;tenants&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;TryGetValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;tenant&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt;&lt;span&gt; connection&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Results&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;StatusCode&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;StatusCodes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Status403Forbidden&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Results&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Ok&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ResolvedConnection&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Database&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;connection&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Database&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Identity&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Identity&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;connection&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;UserName&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;connection&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Password&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ExpiresAt&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;DateTimeOffset&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;UtcNow&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AddMinutes&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;)));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Run&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;http://localhost:5099&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;TenantConnection&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Database&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; UserName&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Password&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConnectionRequest&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Storage&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Purpose&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Dictionary&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; Scope&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Identity&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; UserName &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; Password &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; AccessToken &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ResolvedConnection&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; ConnectionString &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; Database &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; Schema &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Identity&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; Identity &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;DateTimeOffset&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; ExpiresAt &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Two things in there matter more than the dictionary. It checks a key before it answers, because the answer holds credentials. And it says no to a tenant it doesn’t know. Resolution picks a destination. It isn’t an authorization check on the person asking, so what the endpoint does with a tenant it can’t place is part of your security model. Run it with &lt;code dir=&quot;auto&quot;&gt;dotnet run&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;arc-with-chronicle-behind-it&quot;&gt;Arc, with Chronicle behind it&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;The Arc application does two things per tenant. A command records an &lt;code dir=&quot;auto&quot;&gt;OrderPlaced&lt;/code&gt; event in Chronicle, and another command stores a note in MongoDB. Arc picks the tenant from a header, &lt;code dir=&quot;auto&quot;&gt;x-cratis-tenant-id&lt;/code&gt; by default, and maps it to the Chronicle namespace, so the first command lands in the namespace the kernel placed above. The second goes through Arc’s own connection resolution, which is configured to call the endpoint.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;dotnet&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;web&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-n&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrdersApp&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrdersApp&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;dotnet&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;add&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;package&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--version&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;22.112.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;dotnet&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;add&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;package&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis.Arc.MongoDB&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--version&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;22.112.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; builder &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WebApplication&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;CreateBuilder&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;builder&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AddCratis&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;configureArcBuilder&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; arc &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithMongoDB&lt;/span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;configureChronicleOptions&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; chronicle &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventStore&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;orders&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; app &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Build&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;UseCratis&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Run&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Queries&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MongoDB&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Driver&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderPlaced&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Customer&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Total&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PlaceOrder&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Customer&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Total&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderPlaced&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Customer&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Total&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Note&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Text&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Path&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;/api/notes&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IEnumerable&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Note&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;All&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IMongoCollection&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Note&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; notes&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;notes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Find&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ToList&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AddNote&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Text&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IMongoCollection&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Note&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; notes&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;notes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;InsertOneAsync&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Note&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;NewGuid&lt;/span&gt;&lt;span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Text&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The configuration is the other half. &lt;code dir=&quot;auto&quot;&gt;Cratis:Arc:ConnectionResolution&lt;/code&gt; is the application-wide setting, and Arc’s MongoDB integration reads it. &lt;code dir=&quot;auto&quot;&gt;Server&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;Database&lt;/code&gt; stay as they are for anything the endpoint doesn’t answer, and &lt;code dir=&quot;auto&quot;&gt;DirectConnection&lt;/code&gt; is there because the replica set advertises its Docker name, which your machine can’t reach:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;ConnectionResolution&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Connection&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Resolver&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Http&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Http&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Endpoint&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;http://localhost:5099/connections&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Headers&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;X-Api-Key&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;dev-only-key&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;MongoDB&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Server&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;mongodb://localhost:27017/?authSource=admin&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Database&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;arc&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;DirectConnection&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Run it with &lt;code dir=&quot;auto&quot;&gt;dotnet run --urls http://localhost:5200&lt;/code&gt; and send the same two commands for each tenant:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tenant&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;acme&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;globex&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;initech&lt;/span&gt;&lt;span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;curl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-s&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-X&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;POST&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;http://localhost:5200/api/place-order&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;-H&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;x-cratis-tenant-id: &lt;/span&gt;&lt;/span&gt;&lt;span&gt;$tenant&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-H&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;content-type: application/json&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;-d&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span&gt;\&quot;&lt;/span&gt;&lt;span&gt;customer&lt;/span&gt;&lt;span&gt;\&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;\&quot;&lt;/span&gt;&lt;span&gt;$tenant&lt;/span&gt;&lt;span&gt;-customer&lt;/span&gt;&lt;span&gt;\&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;\&quot;&lt;/span&gt;&lt;span&gt;total&lt;/span&gt;&lt;span&gt;\&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:42}&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;curl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-s&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-X&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;POST&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;http://localhost:5200/api/add-note&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;-H&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;x-cratis-tenant-id: &lt;/span&gt;&lt;/span&gt;&lt;span&gt;$tenant&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-H&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;content-type: application/json&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;-d&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span&gt;\&quot;&lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt;\&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;\&quot;&lt;/span&gt;&lt;span&gt;note for &lt;/span&gt;&lt;span&gt;$tenant&lt;/span&gt;&lt;span&gt;\&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;done&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;img alt=&quot;A diagram titled Where each tenant lands. Three rows. acme goes to the events database orders-acme-namespace and the notes database acme-arc. globex goes to orders-globex-namespace and globex-arc. initech goes to orders-initech-namespace, and its notes are refused. A note reads: Choosing a tenant is not authorizing it.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1800&quot; src=&quot;https://blog.cratis.io/_astro/where-the-tenants-land.B4gp90an_2vSf4x.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Two things decided two ways. The kernel placed the events by rule, and the endpoint placed the notes by answer.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Both commands succeed for &lt;code dir=&quot;auto&quot;&gt;acme&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;globex&lt;/code&gt;. For &lt;code dir=&quot;auto&quot;&gt;initech&lt;/code&gt;, the order succeeds and the note fails. Chronicle’s template doesn’t know who’s allowed to exist. It places any namespace it’s asked about, so &lt;code dir=&quot;auto&quot;&gt;initech&lt;/code&gt; got its own events database. The endpoint did know, answered &lt;code dir=&quot;auto&quot;&gt;403&lt;/code&gt;, and Arc refused to open a connection. The kernel and your endpoint don’t coordinate, so checking that a tenant is real belongs in your application, before it touches either. The &lt;a href=&quot;https://blog.cratis.io/tenancy-and-identity-end-to-end/&quot;&gt;tenancy post&lt;/a&gt; goes through why a header isn’t proof of membership.&lt;/p&gt;
&lt;p&gt;Each tenant now reads back only its own notes:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;curl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-s&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;http://localhost:5200/api/notes&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-H&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;x-cratis-tenant-id: acme&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;2a861236-e51d-41f3-93fc-281d08ca1d6f&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;note for acme&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}],&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;isSuccess&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;And the login the endpoint hands out really is limited. This is &lt;code dir=&quot;auto&quot;&gt;acme&lt;/code&gt; trying to read &lt;code dir=&quot;auto&quot;&gt;globex&lt;/code&gt;’s database, and then its own:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;docker&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;compose&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;exec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;mongo&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;mongosh&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-u&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;acme&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-p&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;acme-pw&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--authenticationDatabase&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;admin&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--quiet&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--eval&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;try { db.getSiblingDB(&quot;globex-arc&quot;).getCollection(&quot;Notes&quot;).find().toArray() }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;catch (e) { print(&quot;globex-arc:&quot;, e.codeName) }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;print(&quot;acme-arc:&quot;, db.getSiblingDB(&quot;acme-arc&quot;).getCollection(&quot;Notes&quot;).countDocuments({}))&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;globex-arc: Unauthorized&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;acme-arc: 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;arc-is-optional&quot;&gt;Arc is optional&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Everything Arc did on the application side was ask that endpoint a question and open a connection with the answer. You can do that yourself. This console program knows nothing about Arc. It posts the same request, keeps the answer until a minute before it expires, and builds a MongoDB client with the identity it was given:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;dotnet&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-n&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OwnClient&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OwnClient&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;dotnet&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;add&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;package&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MongoDB.Driver&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--version&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;3.12.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;System&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Collections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Concurrent&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;System&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Net&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Http&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Json&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MongoDB&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Bson&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MongoDB&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Driver&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; resolver &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;TenantConnections&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Uri&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;http://localhost:5099/connections&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;dev-only-key&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;foreach&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; tenant &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;&lt;span&gt;[]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;acme&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;globex&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;initech&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;try&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; notes &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;resolver&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;DatabaseFor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;tenant&lt;/span&gt;&lt;span&gt;&lt;span&gt;))&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;GetCollection&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BsonDocument&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Notes&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;notes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;InsertOneAsync&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BsonDocument&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;_id&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;NewGuid&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ToString&lt;/span&gt;&lt;span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Text&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;$&quot;&lt;/span&gt;&lt;span&gt;own client, &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;tenant&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WriteLine&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;$&quot;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;tenant&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;notes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;CountDocumentsAsync&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;FilterDefinition&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BsonDocument&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Empty&lt;/span&gt;&lt;span&gt;)}&lt;/span&gt;&lt;span&gt;&lt;span&gt; notes&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;catch&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;HttpRequestException&lt;/span&gt;&lt;span&gt;&lt;span&gt; exception&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WriteLine&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;$&quot;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;tenant&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;: refused (&lt;/span&gt;&lt;span&gt;{(&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;?)&lt;/span&gt;&lt;span&gt;exception&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;StatusCode&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Identity&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; UserName&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Password&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Resolved&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Database&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Identity&lt;/span&gt;&lt;span&gt;&lt;span&gt; Identity&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;DateTimeOffset&lt;/span&gt;&lt;span&gt;&lt;span&gt; ExpiresAt&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;TenantConnections&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Uri&lt;/span&gt;&lt;span&gt;&lt;span&gt; endpoint&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; apiKey&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt; Server &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;mongodb://localhost:27017/?authSource=admin&amp;#x26;directConnection=true&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;HttpClient&lt;/span&gt;&lt;span&gt; _http &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;DefaultRequestHeaders&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;X-Api-Key&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;apiKey&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrentDictionary&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Resolved&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; _cache &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;IMongoDatabase&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;DatabaseFor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; tenant&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;_cache&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;TryGetValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;tenant&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;out&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt;&lt;span&gt; resolved&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;resolved&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ExpiresAt&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;DateTimeOffset&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;UtcNow&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AddMinutes&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; response &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_http&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PostAsJsonAsync&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;endpoint&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;storage&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;MongoDB&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;purpose&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Runtime&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;scope&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;tenant&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;response&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EnsureSuccessStatusCode&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;resolved&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_cache&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;tenant&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;response&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Content&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadFromJsonAsync&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Resolved&lt;/span&gt;&lt;span&gt;&gt;())&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; settings &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MongoClientSettings&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;FromConnectionString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Server&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;settings&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Credential&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MongoCredential&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;CreateCredential&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;admin&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;resolved&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Identity&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;UserName&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;resolved&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Identity&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Password&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MongoClient&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;settings&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;GetDatabase&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;resolved&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Database&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;acme: 2 notes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;globex: 2 notes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;initech: refused (403)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;It sees the notes Arc wrote, since they’re in the same database, and &lt;code dir=&quot;auto&quot;&gt;initech&lt;/code&gt; is refused by the same endpoint for the same reason. The code isn’t production code, and the difference between it and Arc is what Arc is for. Arc builds the client and the database from the resolution for each request scope, so the &lt;code dir=&quot;auto&quot;&gt;IMongoCollection&amp;#x3C;Note&gt;&lt;/code&gt; in a handler is already the right tenant’s. It caches the way the contract says and drops the cached answer when a login fails, so a rotated credential is picked up on the next attempt. It refreshes an access token when the MongoDB driver asks for one. And one application-wide configuration serves every storage Arc integrates with, so you set it once.&lt;/p&gt;
&lt;p&gt;If you’re on Kotlin, TypeScript, Elixir or anything else, the contract is the thing to hold on to, not Arc’s class names. A client in another language posts the same JSON and builds a connection with the answer, and the endpoint doesn’t know the difference. Chronicle itself, whichever client you use, resolves its own storage on the kernel side as in the Compose file, so a tenant’s events are placed the same way no matter who appends them.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;what-this-doesnt-do&quot;&gt;What this doesn’t do&lt;/h2&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;It doesn’t authorize anyone.&lt;/strong&gt; The &lt;code dir=&quot;auto&quot;&gt;initech&lt;/code&gt; row is the example. A tenant header or tenant id selects a destination, and checking membership is your job before any tenant-scoped work.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It doesn’t move data.&lt;/strong&gt; Changing the resolution of an existing database points Chronicle or Arc at a new place, and the old data stays where it was. In Arc, a resolved &lt;code dir=&quot;auto&quot;&gt;Database&lt;/code&gt; replaces the default &lt;code dir=&quot;auto&quot;&gt;{Database}+{tenant}&lt;/code&gt; naming entirely, including for the default tenant, so switching is a data migration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It doesn’t make secrets safe by itself.&lt;/strong&gt; The endpoint’s answer holds credentials: serve it over HTTPS, authenticate the caller, and prefer short-lived access tokens with an &lt;code dir=&quot;auto&quot;&gt;expiresAt&lt;/code&gt; over long-lived passwords. The example uses plain HTTP and a key in a header because it runs on one machine.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It doesn’t replace the rest of your isolation.&lt;/strong&gt; Arc’s tenant isolation is a separate concern from where a connection goes, and the &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/tenancy/&quot;&gt;Arc tenancy docs&lt;/a&gt; keep the two apart.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;what-to-take-from-this&quot;&gt;What to take from this&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;If your platform already knows where each tenant lives, you no longer have to bend Chronicle’s and Arc’s naming around that. Start with what you can say in configuration. A template covers a naming rule, and it needs no code on either side. Add an endpoint when you need a per-tenant login or a lookup, and write the endpoint once, because the contract is the same for MongoDB and SQL storage.&lt;/p&gt;
&lt;p&gt;Then decide how much of the client you want to own. Arc gives you the caching, the scoping and the pooling for free. A hand-written client gives you the same placement in a few dozen lines and with whatever driver you already use.&lt;/p&gt;
&lt;p&gt;The pages to read next are &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/tenancy/connection-resolution/&quot;&gt;Arc’s connection resolution&lt;/a&gt;, the &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/mongodb/connection-resolution/&quot;&gt;MongoDB page&lt;/a&gt;, &lt;a href=&quot;https://www.cratis.io/chronicle/hosting/configuration/storage-connection-resolution/&quot;&gt;Chronicle’s storage connection resolution&lt;/a&gt; and the &lt;a href=&quot;https://www.cratis.io/arc/connection-resolution-contract/&quot;&gt;contract&lt;/a&gt;. Tell me where it’s still confusing on &lt;a href=&quot;https://discord.gg/kt4AMpV8WV&quot;&gt;Discord&lt;/a&gt;.&lt;/p&gt;
</content:encoded><category>chronicle</category><category>arc</category><category>tenancy</category><category>mongodb</category><category>operations</category></item><item><title>DCB, but not DCB</title><link>https://blog.cratis.io/dcb-but-not-dcb/</link><guid isPermaLink="true">https://blog.cratis.io/dcb-but-not-dcb/</guid><description>Chronicle&apos;s own documentation says it isn&apos;t a DCB event store. So why do I keep using the term? A proposal to drop the acronym and name what we actually want from it: freedom in how events are modeled, one owner for every event, and rules that live with the command.</description><pubDate>Fri, 16 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;div&gt;&lt;h2 id=&quot;tldr&quot;&gt;TL;DR&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Dynamic Consistency Boundary (DCB) is a good idea with an awkward name. What I care about is smaller and easier to explain: model your events however the business needs, make it obvious which one thing owns the events it produces, and let that owner state, per command, what has to hold when it decides. Chronicle and Arc give you a tool for each, and Arc’s new read protection (Arc 22.106, with Chronicle 19.71) makes the most common one a lot less ceremony. &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/chronicle/&quot;&gt;Chronicle’s own documentation&lt;/a&gt; is upfront that it isn’t a DCB event store, and that points at a better vocabulary.&lt;/p&gt;
&lt;p&gt;The C# in this post uses .NET 10, Chronicle 19.73.1 and Arc 22.109.0.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;why-im-retiring-the-acronym&quot;&gt;Why I’m retiring the acronym&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;In March I wrote about Dynamic Consistency Boundaries and how Chronicle fits, on my own blog. The core of the idea is good: a command reads the events it needs, remembers the position of the last one it saw, and appends only if nothing relevant has arrived since. The consistency boundary comes from what the decision used, not from an object you drew up front. The &lt;a href=&quot;https://dcb.events/&quot;&gt;DCB specification&lt;/a&gt; builds an event store around that, with tags on events as the way to say what an event concerns.&lt;/p&gt;
&lt;p&gt;Chronicle doesn’t do it that way, and the docs say so plainly: Chronicle “supports DCB-style decision models and append conditions within its event-source model. It is not a DCB event store.” Each event has exactly one event source id, and tags you add yourself are labels and filters, not part of the consistency check. A fact about two entities is usually written as two events in one atomic append.&lt;/p&gt;
&lt;p&gt;That’s the reason for this post. I’m not asking anyone to stop reading about DCB. The spec is worth knowing, and my &lt;a href=&quot;https://blog.cratis.io/invariants-at-write-time-with-chronicle-constraints/&quot;&gt;constraints post&lt;/a&gt; from last week leaned on it. I’m asking us to stop using it as the name for what Chronicle does, because the name needs a footnote every time. “DCB” has a second problem too: it sounds like a theory you need to subscribe to before you can write a command. You don’t. What you need is three things, and each of them has a plain name.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/three-things-we-want.bKvX6pHn_ZClDzL.webp&quot; alt=&quot;A diagram titled Say these instead of DCB. Three cards: Flexible modeling, the model can change shape; One clear owner, each event has one owner; Rules per command, the command states what must hold. A line underneath reads: DCB covers some of this. Chronicle spells it its own way.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1600&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Three things worth naming. None of them needs the acronym.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This post takes them in turn, shows what Chronicle and Arc give you for each, and ends with where the Decider pattern fits and where it doesn’t. The mechanisms themselves, constraints, scopes, decision reads and aggregates, are covered in depth in &lt;a href=&quot;https://blog.cratis.io/rules-that-hold-when-you-write/&quot;&gt;Part 5 of the Script to stage series&lt;/a&gt;, and the &lt;a href=&quot;https://blog.cratis.io/the-bug-you-never-see/&quot;&gt;Decisions that hold&lt;/a&gt; series takes read protection one rule at a time. This one is about how they fit together and why.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;flexibility-in-modeling&quot;&gt;Flexibility in modeling&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The point of drawing the consistency boundary at decision time, and not at design time, is that you don’t have to guess your access patterns in advance. The classic aggregate root asks you to decide up front which facts belong together. Get it wrong and you either serialize things that never needed it or protect too little. Chronicle gives you smaller pieces to build the boundary from.&lt;/p&gt;
&lt;p&gt;An event belongs to an &lt;strong&gt;event source&lt;/strong&gt;, identified by an &lt;code dir=&quot;auto&quot;&gt;EventSourceId&lt;/code&gt; (or a typed &lt;code dir=&quot;auto&quot;&gt;EventSourceId&amp;#x3C;T&gt;&lt;/code&gt;, so a book isn’t a member in the type system either). On top of that you can add formalized, single-valued stream metadata: an event source type, an event stream type and an event stream id. A concurrency scope can filter on any of those, plus event types, and it can narrow or widen without touching the events themselves. Those four are different from &lt;a href=&quot;https://www.cratis.io/chronicle/concepts/event-metadata-tags/&quot;&gt;custom tags&lt;/a&gt;: custom tags are stored and filterable, but they don’t take part in consistency.&lt;/p&gt;
&lt;p&gt;You can declare that structure once with an &lt;a href=&quot;https://www.cratis.io/chronicle/event-sources/&quot;&gt;event source definition&lt;/a&gt;, which every client in the table below supports and which needs a Chronicle 19.30 kernel. Here an account has streams, and each stream says which dimensions an append to it is checked on. In C# Onboarding is one stream, and Transactions is one stream per month, so the month is part of what an append is checked against. The other tabs are the published declarations from each client’s docs, with their own stream names:&lt;/p&gt;
&lt;starlight-tabs data-sync-key=&quot;language&quot;&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-0&quot; id=&quot;tab-0-0&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-1&quot; id=&quot;tab-0-1&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Kotlin&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-2&quot; id=&quot;tab-0-2&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-3&quot; id=&quot;tab-0-3&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-4&quot; id=&quot;tab-0-4&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Elixir&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-0&quot; aria-labelledby=&quot;tab-0-0&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSequences&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSources&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MoneyDeposited&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;decimal&lt;/span&gt;&lt;span&gt;&lt;span&gt; Amount&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Account&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; Description &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;A customer&apos;s bank account&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; Concurrency &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyDimensions&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventStream&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Onboarding&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; Description &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Opening the account and verifying the customer&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventStream&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Description &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Deposits and withdrawals, one stream per month&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Concurrency &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyDimensions&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyDimensions&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventStreamType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyDimensions&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventStreamId&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AccountEventSource&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IEventSource&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Deposits&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;AppendResult&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Deposit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IEventLog&lt;/span&gt;&lt;span&gt;&lt;span&gt; eventLog&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;&lt;span&gt; accountId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;decimal&lt;/span&gt;&lt;span&gt;&lt;span&gt; amount&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; month&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventLog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;AccountEventSource&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;accountId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MoneyDeposited&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;amount&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventStream&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventStreamId&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;month&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-1&quot; aria-labelledby=&quot;tab-0-1&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.eventSources.ConcurrencyDimension&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.eventSources.EventSource&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.eventSources.EventStream&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;name &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;Account&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;description &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;A customer account&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;concurrency &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [ConcurrencyDimension.EventSourceId],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;streams &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;EventStream&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;name &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;Transactions&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;description &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;Money in and out&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;concurrency &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ConcurrencyDimension.EventSourceId,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ConcurrencyDimension.EventStreamType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;EventStream&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Settings&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AccountEventSource&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-2&quot; aria-labelledby=&quot;tab-0-2&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eventSources&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ConcurrencyDimension&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eventSources&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSource&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eventSources&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventStream&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Account&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;description&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;A customer account&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;concurrency&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyDimension&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;streams&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventStream&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;description&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Money in and out&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;concurrency&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ConcurrencyDimension&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ConcurrencyDimension&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventStreamType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventStream&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Settings&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AccountEventSource&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-3&quot; aria-labelledby=&quot;tab-0-3&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ConcurrencyDimensions&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventSource&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventStream&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/chronicle&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventSource&lt;/span&gt;&lt;span&gt;&lt;span&gt;({&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;Account&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; description&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;A bank account&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; concurrency&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ConcurrencyDimensions&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eventSourceId&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventStream&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; description&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;Money movements&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AccountEventSource&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-4&quot; aria-labelledby=&quot;tab-0-4&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AccountEventSource&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSources&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSource&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Account&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;description&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;A bank account&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;concurrency&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;event_source_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;stream &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;description&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Money movements&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;concurrency&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;event_source_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;event_stream_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;starlight-tabs-restore&gt;&lt;/starlight-tabs-restore&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;A deposit in April and a deposit in May don’t contend. The guard is asymmetric, though: a deposit doesn’t look at onboarding events, but an onboarding append is checked against every event of the account, deposits included. The first deposit into a brand-new month has nothing to compare against, so by default it isn’t checked at all; you opt in with &lt;code dir=&quot;auto&quot;&gt;CheckFirstAppendIntoAScope&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;ExpectingNoMatchingEvent()&lt;/code&gt; (&lt;code dir=&quot;auto&quot;&gt;withExpectsNoMatchingEvent()&lt;/code&gt; in Kotlin and Java, &lt;code dir=&quot;auto&quot;&gt;EventSequenceNumber.beforeFirst&lt;/code&gt; in TypeScript, &lt;code dir=&quot;auto&quot;&gt;check_first_append&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;ConcurrencyScope.expecting_no_matching_event/1&lt;/code&gt; in Elixir). Nobody had to restructure an aggregate to get this shape, and you can change which dimensions guard an append by editing the declaration. Events that are already stored keep the stream names they were written with. The &lt;a href=&quot;https://www.cratis.io/chronicle/event-sources/concurrency/&quot;&gt;event source docs&lt;/a&gt; show the full conflict table.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/one-source-many-streams.B-U22vaD_2ggWDz.webp&quot; alt=&quot;A diagram titled One source, several streams. A card labeled Account 42, one event source, leads to three streams: Onboarding, Transactions 2026-04 and Transactions 2026-05. A line underneath reads: A stream’s guard covers what its dimensions say.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1900&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;One identity, several streams. Each stream’s guard covers the dimensions it declares.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You can also build a scope by hand when you need one. It states what an append expects about the history it was decided on: a position, plus the event source, stream and event types that matter. Narrower scopes mean fewer false conflicts. Each tab builds a scope from a position and a stream type, and the C#, TypeScript and Elixir ones also name the event types it watches. The &lt;code dir=&quot;auto&quot;&gt;15&lt;/code&gt; stands for the tail position you captured before reading:&lt;/p&gt;
&lt;starlight-tabs data-sync-key=&quot;language&quot;&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-1-0&quot; id=&quot;tab-1-0&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-1-1&quot; id=&quot;tab-1-1&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Kotlin&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-1-2&quot; id=&quot;tab-1-2&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-1-3&quot; id=&quot;tab-1-3&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-1-4&quot; id=&quot;tab-1-4&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Elixir&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-1-0&quot; aria-labelledby=&quot;tab-1-0&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSequences&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSequences&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Concurrency&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyMoneyDeposited&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;decimal&lt;/span&gt;&lt;span&gt;&lt;span&gt; Amount&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyMoneyWithdrawn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;decimal&lt;/span&gt;&lt;span&gt;&lt;span&gt; Amount&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyAccountTransactionService&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IEventLog&lt;/span&gt;&lt;span&gt;&lt;span&gt; eventLog&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ProcessTransaction&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;&lt;span&gt; accountId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;decimal&lt;/span&gt;&lt;span&gt;&lt;span&gt; amount&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; concurrencyScope &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyScopeBuilder&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithEventSourceId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;accountId&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithSequenceNumber&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;15&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithEventStreamType&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithEventType&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;ConcurrencyMoneyDeposited&lt;/span&gt;&lt;span&gt;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithEventType&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;ConcurrencyMoneyWithdrawn&lt;/span&gt;&lt;span&gt;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Build&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;eventLog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;accountId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyMoneyDeposited&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;amount&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;concurrencyScope&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;concurrencyScope&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-1-1&quot; aria-labelledby=&quot;tab-1-1&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.IEventStore&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.events.EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.eventSequences.AppendOptions&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.eventSequences.EventSequenceNumber&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.eventSequences.concurrency.ConcurrencyScopeBuilder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyMoneyDeposited&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; amount: &lt;/span&gt;&lt;span&gt;Double&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0.0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;suspend&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;processTransaction&lt;/span&gt;&lt;span&gt;(store: &lt;/span&gt;&lt;span&gt;IEventStore&lt;/span&gt;&lt;span&gt;, accountId: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;, amount: &lt;/span&gt;&lt;span&gt;Double&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; concurrencyScope &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyScopeBuilder&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;withEventSourceId&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;withSequenceNumber&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;EventSequenceNumber&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;15&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;withEventStreamType&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Transactions&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;store.eventLog.&lt;/span&gt;&lt;span&gt;append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;accountId,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;ConcurrencyMoneyDeposited&lt;/span&gt;&lt;span&gt;(amount),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;AppendOptions&lt;/span&gt;&lt;span&gt;(eventStreamType &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;Transactions&quot;&lt;/span&gt;&lt;span&gt;, concurrencyScope &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; concurrencyScope)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-1-2&quot; aria-labelledby=&quot;tab-1-2&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventStore&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eventSequences&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AppendOptions&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eventSequences&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AppendResult&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eventSequences&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;concurrency&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ConcurrencyScope&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eventSequences&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;concurrency&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ConcurrencyScopeBuilder&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;java&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AppendOptionsBuilder&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;java&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ConcurrencyScopeBuilderJavaBridge&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;java&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventLogJavaBridge&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyMoneyDeposited&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;double&lt;/span&gt;&lt;span&gt;&lt;span&gt; amount&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventsConcurrencyBuilder&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;AppendResult&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;processTransaction&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;EventStore&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;store&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;accountId&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;double&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;amount&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;ConcurrencyScope&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;concurrencyScope&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyScopeBuilderJavaBridge&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;withSequenceNumber&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyScopeBuilder&lt;/span&gt;&lt;span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;15&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;withEventSourceId&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;withEventStreamType&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;AppendOptions&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;options&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AppendOptionsBuilder&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eventStreamType&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;concurrencyScope&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;concurrencyScope&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventLogJavaBridge&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;store&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getEventLog&lt;/span&gt;&lt;span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;span&gt; accountId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyMoneyDeposited&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;amount&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;span&gt; options&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-1-3&quot; aria-labelledby=&quot;tab-1-3&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;getEventTypeFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IEventLog&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/chronicle&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;field&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/fundamentals&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyMoneyDeposited&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;field&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Number&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;amount&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;number&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;constructor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;amount&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;number&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;amount&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;amount&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyMoneyWithdrawn&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;field&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Number&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;amount&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;number&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;constructor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;amount&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;number&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;amount&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;amount&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyAccountTransactionService&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;constructor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;private&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;eventLog&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IEventLog&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;processTransaction&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;accountId&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;amount&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;number&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Promise&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eventLog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;accountId&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyMoneyDeposited&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;amount&lt;/span&gt;&lt;span&gt;&lt;span&gt;),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;concurrencyScope&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;sequenceNumber&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;15&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventStreamType&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventTypes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;getEventTypeFor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ConcurrencyMoneyDeposited&lt;/span&gt;&lt;span&gt;&lt;span&gt;),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;getEventTypeFor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ConcurrencyMoneyWithdrawn&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-1-4&quot; aria-labelledby=&quot;tab-1-4&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ConcurrencyMoneyDeposited&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;concurrency-money-deposited&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;amount&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ConcurrencyMoneyWithdrawn&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;concurrency-money-withdrawn&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;amount&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ConcurrencyAccountTransactionService&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ConcurrencyScope&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.{&lt;/span&gt;&lt;span&gt;ConcurrencyMoneyDeposited&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ConcurrencyMoneyWithdrawn&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;process_transaction&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;account_id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; amount&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;# Pipe-able builder helpers compose a scope step by step.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;scope &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;15&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;|&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyScope&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;|&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyScope&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;with_event_source&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;|&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyScope&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;with_event_stream_type&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Transactions&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;|&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ConcurrencyScope&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;with_event_types&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;ConcurrencyMoneyDeposited&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ConcurrencyMoneyWithdrawn&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;append&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;account_id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; %&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ConcurrencyMoneyDeposited&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&lt;span&gt;amount&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; amount&lt;/span&gt;&lt;span&gt;},&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;concurrency_scope&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; scope&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;starlight-tabs-restore&gt;&lt;/starlight-tabs-restore&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;The default differs by client, and that matters more than the syntax. The .NET client checks the window between its tail read and the write unless you say otherwise. The Kotlin, Java, TypeScript and Elixir clients send no check unless you give the append a scope. In .NET, a scope you build yourself from a stream that had no events yet, so there was no position to capture, is checked as “no matching event yet” since Chronicle 19.68 instead of being skipped; &lt;code dir=&quot;auto&quot;&gt;ConcurrencyOptions.SkipIncompleteExplicitScopes&lt;/code&gt; restores the old skip. The &lt;a href=&quot;https://www.cratis.io/chronicle/clients/where-the-clients-differ/&quot;&gt;client differences page&lt;/a&gt; has the details. Even in .NET, that default only covers the short window at commit. It doesn’t bind a decision to the state you read before it, which is the whole subject of the third section.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;one-clear-owner-for-every-event&quot;&gt;One clear owner for every event&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Flexibility on its own turns into a mess. Once events can be shaped any way you like, the question that keeps a codebase understandable is who is allowed to say that this happened.&lt;/p&gt;
&lt;p&gt;My answer is one owner: the command that produces an event, with the event source deciding which stream the event joins. Every event type belongs to the slice that produces it, and the rules for producing it live there too. In a Cratis application that’s a house convention (the event type is declared in the slice that appends it), and Chronicle’s event source model backs it up from the other side: an event has exactly one event source id, so there’s exactly one stream whose history it becomes part of.&lt;/p&gt;
&lt;p&gt;That’s a deliberate limit, and it has a cost. A fact about two entities, say a member taking a loan that affects both the member and the book, is usually two events, one for each event source, appended together in one atomic &lt;code dir=&quot;auto&quot;&gt;AppendMany&lt;/code&gt;. That’s fine when each is a fact in its own entity’s story, a loan on the member and a copy taken from the book. DCB’s tags would let you write one event and tag it with both, and this is the one place where Chronicle gives that up. When it’s really the same fact twice, the &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/chronicle/&quot;&gt;Chronicle docs&lt;/a&gt; suggest looking for one event on one source with a decision read over the other. In practice the limit keeps ownership readable. You never have to ask which of three concepts an event “really” belongs to.&lt;/p&gt;
&lt;p&gt;In Arc the owner is the command, and the command’s return value is the proof. &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; returns the events, Arc appends them in the command’s transaction, and if you return several &lt;code dir=&quot;auto&quot;&gt;EventForEventSourceId&lt;/code&gt; values they commit together or not at all. There’s no &lt;code dir=&quot;auto&quot;&gt;IEventLog&lt;/code&gt; injected into the middle of business logic. The same goes for an Arc aggregate root, which is an owner with explicit state: it rehydrates from its own entity’s stream and commits what it applied. Same idea, different amount of ceremony.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;rules-that-belong-to-the-command&quot;&gt;Rules that belong to the command&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;This is where most of the confusion sits, so I’ll slow down. The question isn’t which feature to use. It’s what kind of rule you have, because different rules need different guards, and the wrong tool fails silently. The command runs, nobody sees an error, and the rule is broken anyway.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/pick-the-guard.DZLi1VQR_Z1K3yLc.webp&quot; alt=&quot;A diagram titled Pick the guard from the rule. Five rule shapes, each paired with the guard for it. A value is unique: constraint. One key’s history: decision read. Two people edit one record: scope from the revision seen. A rare miss is acceptable: repair with a reactor. A hint on screen: plain read.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2100&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The rule decides the tool. Chronicle’s &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/choosing/&quot;&gt;choosing guide&lt;/a&gt; and Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/&quot;&gt;consistency page&lt;/a&gt; carry the full matrix.&lt;/em&gt;&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;uniqueness-belongs-to-the-store&quot;&gt;Uniqueness belongs to the store&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;A value that must be unique, a username or an email or an ISBN, is the one rule that’s best not decided in a command at all. A constraint is checked by the Chronicle kernel when the event is appended, for every writer, and an append that would break it is rejected. It’s a cheap check, every client in the table below has constraints, and it’s why they sit first on every list. I wrote about them in &lt;a href=&quot;https://blog.cratis.io/invariants-at-write-time-with-chronicle-constraints/&quot;&gt;Invariants at write time&lt;/a&gt;, and &lt;a href=&quot;https://blog.cratis.io/rules-that-hold-when-you-write/&quot;&gt;Part 5&lt;/a&gt; shows the declaration in each client. This is what it looks like on an event in C#:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Constraints&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Concepts&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ProjectName&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ConceptAs&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ProjectDescription&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ConceptAs&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ProjectCreated&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;property&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Unique&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ProjectName&lt;/span&gt;&lt;span&gt;&lt;span&gt; Name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ProjectDescription&lt;/span&gt;&lt;span&gt;&lt;span&gt; Description&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;a-rule-over-state-the-read-you-decide-from&quot;&gt;A rule over state: the read you decide from&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Everything else that depends on state needs a read, and here’s the trap. A read model is an answer to “what does this look like now?” It was never promised to be the state a decision was made on. A materialized read model can lag. A passive one is fresh at the moment you read it, but it doesn’t remember where the log was, so an event that lands between your read and your append goes unnoticed. Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/validators/&quot;&gt;validators page&lt;/a&gt; lays out the sequence: two members borrow the last copy at the same time, both validators read one available, both pass, both events are appended.&lt;/p&gt;
&lt;p&gt;This is the part my March post got wrong, and I’d rather fix it in public. It showed a validator reading a read model to enforce a business rule and presented that as the DCB way. In Chronicle and Arc as they were then, that guarded nothing, and the post also described the default append check incorrectly. Since then Arc has changed what that pattern can mean, which I’ll get to in a moment. A read model is still the right thing for a hint on screen. By default it’s still the wrong thing to decide from.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/plain-read-vs-decision-read.CZjEop9C_Z1hmMYF.webp&quot; alt=&quot;A diagram titled A fresh read is not a guard. Two lanes. Plain read: read the model, another writer appends, the append succeeds, and both writes get through. Decision read: note the position, read, the append is checked against that position, and the second append is rejected.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1800&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The difference is the position. A decision read notes where the log was before it read.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A &lt;a href=&quot;https://www.cratis.io/chronicle/read-models/decision-reads/&quot;&gt;decision read&lt;/a&gt; folds a flat projection from the log in a fresh session and notes the log position first. The append it guards is then rejected if a matching event arrived after that position. An absent model is guarded too, so a concurrent creation conflicts. Decision reads need Chronicle 19.9 or later, and in Arc you opt a command in with &lt;code dir=&quot;auto&quot;&gt;[ProtectedDecision]&lt;/code&gt; from Arc 22.39, take the state as &lt;code dir=&quot;auto&quot;&gt;DecisionRead&amp;#x3C;T&gt;&lt;/code&gt;, and return the event, or a &lt;code dir=&quot;auto&quot;&gt;Result&lt;/code&gt; that declines:&lt;/p&gt;
&lt;starlight-tabs data-sync-key=&quot;language&quot;&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-2-0&quot; id=&quot;tab-2-0&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-2-1&quot; id=&quot;tab-2-1&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Kotlin&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-2-2&quot; id=&quot;tab-2-2&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-2-3&quot; id=&quot;tab-2-3&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-2-4&quot; id=&quot;tab-2-4&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Elixir&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-2-0&quot; aria-labelledby=&quot;tab-2-0&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Validation&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Concepts&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Monads&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ConceptAs&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopyAdded&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; MemberId&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Increment&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;CopyAdded&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Decrement&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Increment&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Available&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;ProtectedDecision&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;&lt;span&gt; BookId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; MemberId&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Result&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ValidationResult&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;DecisionRead&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookStock&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; stock&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;stock&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;not&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Available&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ValidationResult&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;No copies of this book are available.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-2-1&quot; aria-labelledby=&quot;tab-2-1&quot; role=&quot;tabpanel&quot; tabindex=&quot;0&quot; hidden&gt;&lt;p&gt;Kotlin does not support decision reads yet.&lt;/p&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-2-2&quot; aria-labelledby=&quot;tab-2-2&quot; role=&quot;tabpanel&quot; tabindex=&quot;0&quot; hidden&gt;&lt;p&gt;Java does not support decision reads yet.&lt;/p&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-2-3&quot; aria-labelledby=&quot;tab-2-3&quot; role=&quot;tabpanel&quot; tabindex=&quot;0&quot; hidden&gt;&lt;p&gt;TypeScript does not support decision reads yet.&lt;/p&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-2-4&quot; aria-labelledby=&quot;tab-2-4&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;p&gt;Arc for Elixir doesn’t exist. With the Chronicle Elixir client, &lt;code dir=&quot;auto&quot;&gt;Chronicle.decide/2&lt;/code&gt; runs the read and the guarded append in one unit of work:&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;decide&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;fn&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_unit_of_work&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;ok&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; read&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;DecisionReads&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Seat&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;seat-5&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; read&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;instance &lt;/span&gt;&lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nil&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSequences&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventLog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;append&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;seat-5&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; %&lt;/span&gt;&lt;/span&gt;&lt;span&gt;SeatBooked&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;&lt;span&gt;by&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;alice&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;starlight-tabs-restore&gt;&lt;/starlight-tabs-restore&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;If two members race for the last copy, the second one gets a validation result with the reason &lt;code dir=&quot;auto&quot;&gt;concurrencyViolation&lt;/code&gt;. Nothing is appended, and Arc and Chronicle don’t re-run the command. The caller reads again and resubmits. That cost is real: a decision read folds the key’s whole history on every attempt, and the docs advise keeping keys short-lived (a key per period, per order, per booking) and flat. It guards the event log for the keys it reads. Revisions, redactions, other event sequences and data from outside Chronicle aren’t covered. When the rule is about one routed stream of raw events, Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/commands/stream-decisions/&quot;&gt;stream decisions&lt;/a&gt; do the same job without folding a projection.&lt;/p&gt;
&lt;div&gt;&lt;h4 id=&quot;read-protection-the-same-guard-without-the-ceremony&quot;&gt;Read protection: the same guard, without the ceremony&lt;/h4&gt;&lt;/div&gt;
&lt;p&gt;Arc 22.106 added a second way to get the same guard, and for most commands it’s the one I’d reach for first. With read protection switched on, a read model you take as a parameter of a command or its validator is read the way a decision read is: fresh, with the log position noted first. If anything it read changed before the commit, nothing is written and the caller gets a 400 with the same &lt;code dir=&quot;auto&quot;&gt;concurrencyViolation&lt;/code&gt;, the detail &lt;code dir=&quot;auto&quot;&gt;ReadChanged&lt;/code&gt;, and a message saying which read model changed: “BookStock ‘isbn-1’ changed after BorrowBook read it. Nothing from this command was written; submit it again.” It needs Chronicle 19.71 or later, and it’s off by default, so nothing changes until you ask. New applications from the Cratis templates start with it &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;. You turn it on for the whole assembly with &lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;CratisReadProtection&gt;On&amp;#x3C;/CratisReadProtection&gt;&lt;/code&gt;, or for one command with &lt;code dir=&quot;auto&quot;&gt;[ReadProtection(ReadProtectionMode.On)]&lt;/code&gt;. There’s a &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; mode that changes no behavior and reports what &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; would guard or refuse, which is how I’d adopt it in an existing application.&lt;/p&gt;
&lt;p&gt;The practical difference is where the rule lives. With a protected decision it’s in &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt;. With read protection the rule can sit in an ordinary &lt;code dir=&quot;auto&quot;&gt;CommandValidator&amp;#x3C;T&gt;&lt;/code&gt;, the read model arrives as a constructor parameter, and &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; only says what happens:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Queries&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Concepts&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;FluentValidation&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ConceptAs&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CopyAdded&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Member&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Member&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStock&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Increment&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;CopyAdded&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Decrement&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Increment&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Available&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ReadProtection&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ReadProtectionMode&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;On&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt; Isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Member&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Member&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowBookValidator&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CommandValidator&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowBookValidator&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BookStock&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; stock&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;RuleFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;command &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Must&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;stock&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Available&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithMessage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;No copies of this book are available.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;BookStock?&lt;/code&gt; is nullable because a book with no events has no read model yet; a non-nullable parameter refuses the command before any rule runs. Let convention discovery register the validator: under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, one you register by hand as scoped, as a singleton, through a factory or as an instance is refused.&lt;/p&gt;
&lt;p&gt;That’s the March pattern, and under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; it holds. The same code under the default &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; is a plain read again, which is why I’d rather the mode be visible on the command than hidden in a build property you forget about. When a read is meant as a hint, &lt;code dir=&quot;auto&quot;&gt;[Unprotected(&quot;why&quot;)]&lt;/code&gt; says so, and under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; reads Arc can’t protect, such as a raw event log read, are refused with a message that says why. From Arc 22.108, a command declared &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; also blocks on validator errors whatever severity the caller asks to allow with &lt;code dir=&quot;auto&quot;&gt;X-Allowed-Severity&lt;/code&gt;; under &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt; a caller can drop them unless the command declares &lt;code dir=&quot;auto&quot;&gt;[BlockOnValidationSeverity(ValidationResultSeverity.Error)]&lt;/code&gt;. &lt;code dir=&quot;auto&quot;&gt;[ProtectedDecision]&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;DecisionRead&amp;#x3C;T&gt;&lt;/code&gt; keep working, but under &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; you don’t need them.&lt;/p&gt;
&lt;p&gt;It’s .NET only, like &lt;code dir=&quot;auto&quot;&gt;[ProtectedDecision]&lt;/code&gt;. The &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/getting-started/&quot;&gt;Arc getting started guide&lt;/a&gt; walks through it and &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/adopting/&quot;&gt;adopting read protection&lt;/a&gt; covers &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;. The cost is the one decision reads have: the read folds the history it covers on every attempt, and nothing re-runs the command for you.&lt;/p&gt;
&lt;p&gt;Chronicle 19.71 also fixed the cost problem I mentioned for long histories. A read model can declare the one stream that defines its state with &lt;code dir=&quot;auto&quot;&gt;[EventStream&amp;#x3C;TSource&gt;(stream)]&lt;/code&gt;, say a month of withdrawals. Taken as a plain parameter, it’s read from the stream the command’s route points to, so October’s withdrawals don’t make November’s command conflict. That’s the “key per period” advice, without inventing a key. Arc’s &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/scenarios/per-stream/&quot;&gt;one stream&lt;/a&gt; scenario has the monthly-limit example.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;validators-check-the-input-and-with-read-protection-a-bit-more&quot;&gt;Validators check the input, and with read protection a bit more&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Validation is the one most people already know, and it keeps its job. A validator checks the shape of the input, and a shape check has no state to race. Arc 22.106 adds one thing: under read protection &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, a validator that takes a read model also guards that read, which the section above shows. In C# that’s &lt;code dir=&quot;auto&quot;&gt;CommandValidator&amp;#x3C;T&gt;&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;ConceptValidator&amp;#x3C;T&gt;&lt;/code&gt; with FluentValidation rules, which Arc also maps into the generated TypeScript proxies so the browser can check the same thing. Arc for Kotlin and Java has a &lt;code dir=&quot;auto&quot;&gt;CommandValidator&lt;/code&gt; and its own validators, and Arc’s frontend core has a &lt;code dir=&quot;auto&quot;&gt;ruleFor&lt;/code&gt; API that mirrors the common rules. The rule of thumb is the same in all of them:&lt;/p&gt;
&lt;starlight-tabs data-sync-key=&quot;language&quot;&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-3-0&quot; id=&quot;tab-3-0&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-3-1&quot; id=&quot;tab-3-1&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Kotlin&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-3-2&quot; id=&quot;tab-3-2&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-3-3&quot; id=&quot;tab-3-3&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-3-4&quot; id=&quot;tab-3-4&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Elixir&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-3-0&quot; aria-labelledby=&quot;tab-3-0&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;FluentValidation&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowBookValidator&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CommandValidator&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BorrowBook&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BorrowBookValidator&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;RuleFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;command &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;MemberId&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;NotEmpty&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithMessage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;A member is required.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-3-1&quot; aria-labelledby=&quot;tab-3-1&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@Component&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CreateTaskValidator&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;CommandValidator&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;CreateTask&lt;/span&gt;&lt;span&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;override&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; commandType &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; CreateTask::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;.java&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;override&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;suspend&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;validate&lt;/span&gt;&lt;span&gt;(command: &lt;/span&gt;&lt;span&gt;CreateTask&lt;/span&gt;&lt;span&gt;, context: &lt;/span&gt;&lt;span&gt;CommandContext&lt;/span&gt;&lt;span&gt;): &lt;/span&gt;&lt;span&gt;List&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;ValidationResult&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (command.title.&lt;/span&gt;&lt;span&gt;isBlank&lt;/span&gt;&lt;span&gt;()) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;listOf&lt;/span&gt;&lt;span&gt;(ValidationResult.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;A task title is required.&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;listOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;title&quot;&lt;/span&gt;&lt;span&gt;)))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;emptyList&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-3-2&quot; aria-labelledby=&quot;tab-3-2&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CreateTaskValidator&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;implements&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BlockingCommandValidator&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;CreateTask&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Override&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Class&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;CreateTask&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;getCommandType&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CreateTask&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Override&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;List&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;ValidationResult&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;validate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;CreateTask&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CommandContext&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;context&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;isBlank&lt;/span&gt;&lt;span&gt;&lt;span&gt;())&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;List&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;of&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ValidationResult&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;A task title is required.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;List&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;of&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;List&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;of&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Configuration&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ValidationConfiguration&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Bean&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;CommandValidator&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;CreateTask&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;createTaskValidator&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BlockingCommandValidatorAdapter&lt;/span&gt;&lt;span&gt;&amp;#x3C;&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CreateTaskValidator&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-3-3&quot; aria-labelledby=&quot;tab-3-3&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CreateUserCommandValidator&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;extends&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CommandValidator&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;ICreateUserCommand&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;constructor&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;super&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ruleFor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;email&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;notEmpty&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;emailAddress&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ruleFor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;age&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;greaterThanOrEqual&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;18&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ruleFor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;minLength&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;maxLength&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;50&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-3-4&quot; aria-labelledby=&quot;tab-3-4&quot; role=&quot;tabpanel&quot; tabindex=&quot;0&quot; hidden&gt;&lt;p&gt;Arc for Elixir doesn’t exist.&lt;/p&gt;&lt;/div&gt;&lt;starlight-tabs-restore&gt;&lt;/starlight-tabs-restore&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;A validator can take a read model as a constructor dependency, and it’ll run. Whether it guards anything depends on the mode. Under read protection &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; it does, as above. Under the default &lt;code dir=&quot;auto&quot;&gt;Off&lt;/code&gt;, and under &lt;code dir=&quot;auto&quot;&gt;Measure&lt;/code&gt;, it doesn’t, and outside &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; a &lt;code dir=&quot;auto&quot;&gt;[ProtectedDecision]&lt;/code&gt; command only accepts validators with a single parameterless constructor, refusing the rest when the command runs. So the split is clean for a protected decision: the validator says whether the input is well formed, &lt;code dir=&quot;auto&quot;&gt;Provide()&lt;/code&gt; fetches data, and &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; decides, returning events or a &lt;code dir=&quot;auto&quot;&gt;Result&amp;#x3C;TEvent, ValidationResult&gt;&lt;/code&gt; that declines whatever severity the caller allows. With read protection you can instead put the state-dependent rule in the validator. The Arc page on &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/validators/&quot;&gt;validators and consistency&lt;/a&gt; has the full table.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;aggregates-are-one-owner-with-its-own-state&quot;&gt;Aggregates are one owner with its own state&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;I haven’t forgotten aggregate roots. Arc has them, for .NET only, and the docs treat them as a legitimate choice for rich behavior: many rules over one lifecycle, where “withdraw 200” has to be checked against this account’s own history. An aggregate root rehydrates from its entity’s events, applies new facts under its own rules, and commits them as one unit.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Aggregates&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Concepts&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderId&lt;/span&gt;&lt;span&gt; NotSet &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Empty&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderId&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;New&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;NewGuid&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;implicit&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;operator&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ProductId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ProductId&lt;/span&gt;&lt;span&gt; NotSet &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Empty&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ProductId&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;New&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;NewGuid&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;implicit&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;operator&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ProductId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Quantity&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ConceptAs&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Quantity&lt;/span&gt;&lt;span&gt; NotSet &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;implicit&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;operator&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Quantity&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Order&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;AggregateRoot&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; _quantity&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AddItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ProductId&lt;/span&gt;&lt;span&gt;&lt;span&gt; productId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Quantity&lt;/span&gt;&lt;span&gt;&lt;span&gt; quantity&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;#x3C;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_quantity&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;Failed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Quantity must be positive and the order total must not exceed 100.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Apply&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ItemAdded&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;productId&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OnItemAdded&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ItemAdded&lt;/span&gt;&lt;span&gt;&lt;span&gt; @event&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_quantity&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;@event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Quantity&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ItemAdded&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ProductId&lt;/span&gt;&lt;span&gt;&lt;span&gt; ProductId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Quantity&lt;/span&gt;&lt;span&gt;&lt;span&gt; Quantity&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Arc takes the stream’s position when it rehydrates and guards the commit with a scope built from it, so an aggregate rests on scopes, not on decision reads. It’s a good fit when the rules belong together on one key. It’s more than you need when one counter rule would do, and the docs say as much. They also say you can’t mix an aggregate with &lt;code dir=&quot;auto&quot;&gt;[ProtectedDecision]&lt;/code&gt; on the same command. Under read protection &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt;, a command can take an aggregate and a read model of a different source; a read of the aggregate’s own source is refused.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;where-the-decider-fits&quot;&gt;Where the Decider fits&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;If you know Jérémie Chassaing’s &lt;a href=&quot;https://thinkbeforecoding.com/post/2021/12/17/functional-event-sourcing-decider&quot;&gt;Decider pattern&lt;/a&gt;, here’s where I’d place all this. A decider is a decide function from a command and a state to events, an evolve function from a state and an event to a new state, an initial state, and a way to tell when the process is finished. Nothing in the Cratis docs calls Chronicle or Arc a decider, so this mapping is mine, and I’d say a protected-decision command reminds me of one more than it implements one.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/decider-map.XAOaBU-5_Z1zDMHW.webp&quot; alt=&quot;A diagram titled Decider, in Cratis terms. decide maps to Handle on a protected command. evolve maps to a projection or an aggregate On method. initial state maps to an absent read model. terminal maps to closing a stream. A line underneath reads: Resembles a decider; isn’t one.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2100&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Where the four parts of a decider land. The fit is loose, and the gaps matter.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;decide&lt;/code&gt; is &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt;, with the state coming in as &lt;code dir=&quot;auto&quot;&gt;DecisionRead&amp;#x3C;T&gt;&lt;/code&gt; and the events going out as the return value. With read protection it can also be a validator over a read-model parameter plus a &lt;code dir=&quot;auto&quot;&gt;Handle()&lt;/code&gt; that says what happens, which is a looser fit. &lt;code dir=&quot;auto&quot;&gt;evolve&lt;/code&gt; is the projection that builds the state, or an aggregate’s &lt;code dir=&quot;auto&quot;&gt;On&lt;/code&gt; methods. The initial state is the absent model: &lt;code dir=&quot;auto&quot;&gt;Instance&lt;/code&gt; is null, and an absent model is guarded too. The nearest thing to a terminal state is &lt;a href=&quot;https://www.cratis.io/chronicle/closing-streams/&quot;&gt;closing a stream&lt;/a&gt;, which the kernel enforces as a constraint.&lt;/p&gt;
&lt;p&gt;The differences matter. A decider composes: you can combine two and map over them. Chronicle doesn’t offer that, and a decision read refuses projections that join entities, so a rule over two keys is two decision reads (with read protection, two read-model parameters with &lt;code dir=&quot;auto&quot;&gt;[LookUpBy]&lt;/code&gt;) and one or two events in one &lt;code dir=&quot;auto&quot;&gt;AppendMany&lt;/code&gt;. The guard lives in the store as the append condition and not in the decider’s type. Uniqueness, which a decider can’t express without the whole set of values as its state, sits outside it entirely as a constraint. And a decision read folds the key’s history from the log on every attempt, where a decider’s state is just whatever you carried forward. So if “decider” helps you design a command, use it. I wouldn’t promise anyone the whole pattern.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;what-each-client-has&quot;&gt;What each client has&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The three capabilities don’t arrive at the same time in every language. This is what’s in the released clients and Arc ports named here:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;.NET&lt;/th&gt;
&lt;th&gt;Kotlin / Java&lt;/th&gt;
&lt;th&gt;TypeScript&lt;/th&gt;
&lt;th&gt;Elixir&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Constraints (&lt;code dir=&quot;auto&quot;&gt;unique&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Concurrency scopes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default append check&lt;/td&gt;
&lt;td&gt;Optimistic tail read&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Event source definitions&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decision reads&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Closing-stream constraint&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read protection (&lt;code dir=&quot;auto&quot;&gt;[ReadProtection]&lt;/code&gt;, Arc 22.106)&lt;/td&gt;
&lt;td&gt;Arc for .NET&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No Arc&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;[ProtectedDecision]&lt;/code&gt;, aggregate roots&lt;/td&gt;
&lt;td&gt;Arc for .NET&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No Arc&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Command validators&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;CommandValidator&amp;#x3C;T&gt;&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;ConceptValidator&amp;#x3C;T&gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;CommandValidator&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;ConceptValidator&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Arc’s frontend core only&lt;/td&gt;
&lt;td&gt;No Arc&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;If you’re not on .NET, the practical advice is the same one the docs give: use constraints for uniqueness, pass an explicit scope built from a position you captured before you read, and keep rules that need a decision read in a .NET service for now. Plainly: the clients aren’t interchangeable, and the decision capabilities haven’t reached all of them yet.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;what-to-do-on-monday&quot;&gt;What to do on Monday&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;You don’t need to adopt anything to use this. For the next command you write, ask three questions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Who owns this?&lt;/strong&gt; Which slice produces the event, and is it the only one? If a fact concerns two entities, are you ready to write two events in one append?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What has to hold when it’s decided?&lt;/strong&gt; Name the rule. Is it a unique value, a rule over one key’s history, a conflict between two people editing, or something that’s fine to repair afterward?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Which row of &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/&quot;&gt;Arc’s decision matrix&lt;/a&gt; is that?&lt;/strong&gt; Constraint, decision read, stream decision, explicit scope, aggregate or a repair. If your answer is “I read a read model first”, either turn on read protection for that command or accept that you’re shipping a hint and calling it a rule.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From there, &lt;a href=&quot;https://blog.cratis.io/rules-that-hold-when-you-write/&quot;&gt;Part 5&lt;/a&gt; goes deep on each mechanism, the &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/chronicle/consistency/&quot;&gt;consistency page in Arc’s docs&lt;/a&gt; has the decision matrix and the list of failures that are silent, and the &lt;a href=&quot;https://www.cratis.io/chronicle/dynamic-consistency-boundary/&quot;&gt;Chronicle DCB page&lt;/a&gt; is the place to start if you want the original idea. Tell me where this is still confusing on &lt;a href=&quot;https://discord.gg/kt4AMpV8WV&quot;&gt;Discord&lt;/a&gt;.&lt;/p&gt;</content:encoded><category>chronicle</category><category>arc</category><category>event-sourcing</category><category>constraints</category><category>concurrency</category></item><item><title>Inside Cratis Studio: built on the platform it&apos;s for</title><link>https://blog.cratis.io/studio-architecture/</link><guid isPermaLink="true">https://blog.cratis.io/studio-architecture/</guid><description>A walkthrough of how Cratis Studio is built: the services and what each one owns, the edge and the lobby in front of them, four event stores that talk in facts, and the infrastructure underneath. Studio is built with the platform it&apos;s meant to help you use.</description><pubDate>Fri, 16 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;div&gt;&lt;h2 id=&quot;tldr&quot;&gt;TL;DR&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Cratis Studio is a handful of services in front of a Chronicle event store: an edge (&lt;a href=&quot;https://blog.cratis.io/authproxy-the-edge-your-services-should-not-build/&quot;&gt;AuthProxy&lt;/a&gt;) that signs you in and works out which organization you belong to, a lobby (&lt;a href=&quot;https://github.com/Cratis/Ante&quot;&gt;Ante&lt;/a&gt;) that handles invitations, and the Studio application itself. Core, the lobby, the admin console and the catalog each keep their own event store, and they pass each other facts. Studio is built with Chronicle, Arc, Components and the rest of the platform.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;why-show-the-architecture&quot;&gt;Why show the architecture&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Cratis Studio is a collaborative workspace where &lt;a href=&quot;https://blog.cratis.io/cratis-studio-event-modeling-together/&quot;&gt;people and AI agents design, visualize and edit the same event model&lt;/a&gt;. That post is about what you can do with it. This one is about what’s behind it, because Studio is also a real application built on the same packages you’d install, and I think showing how it’s put together is the most honest way to show what those packages are for.&lt;/p&gt;
&lt;p&gt;I’ll keep this at the level of shapes and responsibilities.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-shape-of-it&quot;&gt;The shape of it&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/studio-at-a-glance.BT3FtqZi_ZL27Gz.webp&quot; alt=&quot;A diagram titled Cratis Studio at a glance. A browser and an external AI agent both pass through AuthProxy, which handles sign-in, organization and identity. Behind it sit Core, with MCP as a way in for AI agents, and the lobby, Ante. Core and the lobby record into Chronicle, one event store per service. A note lists the admin console, catalog, viewer and GitHub integration as further services.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2300&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The edge sits in front of the product. Chronicle is where the facts live.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The services, and what each one is for:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Core&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The product: the event-model board and canvas, projects and domains, live collaboration, the AI agents, Play and code generation, and the people in an organization.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lobby&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/Cratis/Ante&quot;&gt;Ante&lt;/a&gt; as a published image. Invitations and the acceptance of legal terms.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AuthProxy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The edge. Sign-in, organization and identity for the services behind it.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MCP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The MCP server Studio offers external AI agents to read and change an organization’s event models and brainstorming boards.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Admin&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Internal tooling for running Studio.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Catalog&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The product catalog.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Viewer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A read-only viewer of an event model.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GitHub integration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Connects Studio to GitHub.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;There’s no separate “workers” service. The background work runs inside Core.&lt;/p&gt;
&lt;p&gt;Studio doesn’t ship a language model. Cratis Studio’s AI agents can generate modules, features and slices from a prompt, explain a domain, feature or module, and answer in chat on the model. They run on a model provider your organization configures, and AI stays off until one is set up.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-request-path&quot;&gt;The request path&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/the-request-path.DZpRByjO_Z1a9fqT.webp&quot; alt=&quot;A diagram titled The path of a request. Five boxes in a path. Browser, then Ingress with TLS, then AuthProxy, which signs you in and finds your organization, then Core, which decides what you may do, then a Chronicle namespace holding your organization’s own events. A line underneath reads: Organization, tenant, namespace: one thing.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2100&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;One path in, one namespace out.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A request arrives over TLS at the ingress and is handed to AuthProxy. AuthProxy does the work every service would otherwise repeat: it signs the user in through the identity provider, works out which organization they’re working in, and forwards the request with the identity and the tenant attached. The &lt;a href=&quot;https://blog.cratis.io/authproxy-the-edge-your-services-should-not-build/&quot;&gt;AuthProxy post&lt;/a&gt; explains how that works and what it asks of the services behind it, and &lt;a href=&quot;https://blog.cratis.io/tenancy-and-identity-end-to-end/&quot;&gt;multi-tenancy and identity end to end&lt;/a&gt;, Part 10 of the &lt;a href=&quot;https://blog.cratis.io/from-the-edge-to-the-event-log/&quot;&gt;series&lt;/a&gt;, follows the same request all the way down.&lt;/p&gt;
&lt;p&gt;What matters for the architecture is what happens next. Studio maps the tenant to a Chronicle namespace, so an organization, a tenant and a namespace are the same thing. Each Chronicle &lt;a href=&quot;https://www.cratis.io/chronicle/concepts/namespaces/&quot;&gt;namespace&lt;/a&gt; has its own events, observers and read models, so Studio keeps each organization’s events in its own namespace.&lt;/p&gt;
&lt;p&gt;Authorization stays in the application. AuthProxy establishes who you are and which organization you’re in. Core decides what you’re allowed to do, with Arc command and query filters, because the edge doesn’t know the rules of the domain and shouldn’t.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;four-event-stores-and-facts-between-them&quot;&gt;Four event stores, and facts between them&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/four-event-stores.v0-V4xDD_Z14pAK2.webp&quot; alt=&quot;A diagram titled Four event stores. Core, which has a namespace per organization, Lobby, Admin and Catalog each hold their own event store. Between Core and Lobby, two arrows carry facts: invitation requested, and invitation accepted. A line underneath reads: Services share facts.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2000&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Each service owns its store. Facts cross the boundary as events.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Studio doesn’t have one big event store with every service poking at it. Core, the lobby, the admin console and the catalog each have their own, and they talk the way a reactor reacts inside one store: something happened, and somebody else cares. Chronicle’s outbox and inbox carry a fact from one store to another. It means each store’s history is about one thing. The cost of that split is the usual one: the owner of a fact has to decide to publish it, and the consumer has to cope with it arriving later.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-lobby-and-one-invitation-end-to-end&quot;&gt;The lobby, and one invitation end to end&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/an-invitation.t3rMdX5B_Z7MOaC.webp&quot; alt=&quot;A diagram titled An invitation, end to end. Six steps. One: Core records the invitation. Two: a reactor asks the lobby. Three: Ante signs the link. Four: Core emails it. Five: the invitee signs in through AuthProxy. Six: the lobby records acceptance and Core adds the user.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1700&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Every hand-off in this flow is an event.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The lobby is where a person who isn’t in an organization yet ends up. Studio runs &lt;a href=&quot;https://github.com/Cratis/Ante&quot;&gt;Ante&lt;/a&gt; for this, which was extracted from Studio’s lobby and is published as its own image: it signs invitations, hosts the acceptance screens, and coordinates through events. Walking an invitation through shows how the pieces cooperate.&lt;/p&gt;
&lt;p&gt;An organization member invites someone. Core handles &lt;code dir=&quot;auto&quot;&gt;InviteUser&lt;/code&gt; and records &lt;code dir=&quot;auto&quot;&gt;UserInvitedToJoinOrganization&lt;/code&gt;. The email address in that event is personal data, handled the way &lt;a href=&quot;https://blog.cratis.io/personal-data-in-an-event-log/&quot;&gt;personal data in an event log&lt;/a&gt; describes. A unique constraint on the email is checked when the event is appended, so a second invitation to the same address is rejected. A reactor in Core then appends a fact for the lobby’s inbox, Ante signs the invitation link and answers with another fact, and Core sends the email. The invitee opens the link, signs in through AuthProxy, and the lobby records that the invitation was accepted. A reactor in Core listens for that and provisions the user inside the organization’s namespace, with a role.&lt;/p&gt;
&lt;p&gt;Between Core and the lobby, every hand-off in that story is an event, and every step is something you could replay or look at in the log.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;built-on-the-platform-its-for&quot;&gt;Built on the platform it’s for&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/built-on-the-platform.BsD7I7G5_Z1d4axc.webp&quot; alt=&quot;A diagram titled What Studio uses from the platform. Six rows pairing a part of the platform with what Studio does with it. Chronicle: a namespace per organization. Arc: commands and live queries. Components: the React interface. Fundamentals: concepts like ProjectName. AuthProxy and Ante: the edge and the lobby. Stage and Screenplay: Play and code generation.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2300&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The published packages Studio is built with.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Studio is built with Chronicle, Arc, Components, Fundamentals, AuthProxy and Ante, and its Play and code generation features use Stage, Screenplay and Scene.&lt;/p&gt;
&lt;p&gt;Here’s what a small slice looks like. This is registering a project, trimmed down: a command that returns a fact, a constraint that keeps names unique, and a read model that fills itself from the events and exposes a live query.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Commands&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Queries&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Constraints&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Keys&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Concepts&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MongoDB&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Driver&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;System&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Reactive&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Subjects&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ProjectId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ProjectId&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;New&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;NewGuid&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;implicit&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;operator&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ProjectId&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ProjectName&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ConceptAs&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;implicit&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;operator&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ProjectName&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ProjectDescription&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ConceptAs&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;implicit&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;operator&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ProjectDescription&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; value&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ProjectRegistered&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ProjectName&lt;/span&gt;&lt;span&gt;&lt;span&gt; Name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ProjectDescription&lt;/span&gt;&lt;span&gt;&lt;span&gt; Description&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ProjectRemoved&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;RegisterProject&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ProjectName&lt;/span&gt;&lt;span&gt;&lt;span&gt; Name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ProjectDescription&lt;/span&gt;&lt;span&gt;&lt;span&gt; Description&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ProjectId&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IEnumerable&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;EventForEventSourceId&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; projectId &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ProjectId&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;New&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;projectId&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;projectId&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ProjectRegistered&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Name&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Description&lt;/span&gt;&lt;span&gt;))]);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;UniqueProjectNameConstraint&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IConstraint&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Define&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IConstraintBuilder&lt;/span&gt;&lt;span&gt;&lt;span&gt; builder&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Unique&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;unique &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;unique&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithName&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;UniqueProjectName&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;On&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;ProjectRegistered&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;@event &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;@event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Name&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;RemovedWith&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;ProjectRemoved&lt;/span&gt;&lt;span&gt;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WithMessage&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;A project with this name already exists.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;FromEvent&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;ProjectRegistered&lt;/span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;RemovedWith&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;ProjectRemoved&lt;/span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Project&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;ProjectId&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ProjectName&lt;/span&gt;&lt;span&gt;&lt;span&gt; Name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ProjectDescription&lt;/span&gt;&lt;span&gt;&lt;span&gt; Description&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ISubject&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;IEnumerable&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Project&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;AllProjects&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IMongoCollection&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Project&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; collection&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;collection&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Observe&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ISubject&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Project&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ProjectById&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;Key&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;ProjectId&lt;/span&gt;&lt;span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IMongoCollection&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Project&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; collection&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;collection&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ObserveById&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The slice targets .NET 10 and the &lt;code dir=&quot;auto&quot;&gt;Cratis&lt;/code&gt; metapackage 22.101.0. That’s the whole slice. The command says what happened and nothing else. The name rule is checked by the kernel when the event is appended, not in the command. The read model is built from the events and pushed to the browser as an observable query, which is how the project tree stays current while someone else is editing. Arc generates a TypeScript proxy for the command and the query, and the React side uses it. The post on &lt;a href=&quot;https://blog.cratis.io/from-event-to-read-model/&quot;&gt;read models&lt;/a&gt; and &lt;a href=&quot;https://blog.cratis.io/live-uis-with-arc/&quot;&gt;live UIs with Arc&lt;/a&gt; go through each piece.&lt;/p&gt;
&lt;p&gt;A few other places the platform shows up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Concepts, not primitives.&lt;/strong&gt; &lt;code dir=&quot;auto&quot;&gt;ProjectName&lt;/code&gt; isn’t a string. Fundamentals’ &lt;code dir=&quot;auto&quot;&gt;ConceptAs&amp;#x3C;T&gt;&lt;/code&gt; keeps a project name from being a description by accident, in the command, the event and the read model.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reactors for everything that follows.&lt;/strong&gt; Provisioning a user after an acceptance and emailing a link are each a reactor reacting to a fact, &lt;a href=&quot;https://blog.cratis.io/reacting-to-facts/&quot;&gt;the way Part 4 describes&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reducers where the fold is easier as code.&lt;/strong&gt; A few read models build their state from events in a method instead of a declaration, for the cases where &lt;a href=&quot;https://blog.cratis.io/reducers-full-control-persistence-for-free/&quot;&gt;a reducer reads better than a projection&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Orleans.&lt;/strong&gt; The services that need it co-host an Orleans silo, using the shared Cratis Orleans packages.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;what-the-architecture-carries&quot;&gt;What the architecture carries&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Three features sit on top of all this.&lt;/p&gt;
&lt;p&gt;In Cratis Studio a team brainstorms events on a shared board, models commands, events and read models on one canvas, and sees everyone’s cursor as they work. The model itself arrives the way every read model in Studio does, as an observable query.&lt;/p&gt;
&lt;p&gt;Cratis Studio has an MCP server that lets external AI agents read and change an organization’s event models and brainstorming boards. Studio’s own agents go through the same surface, so there’s one way in to the model, whether the caller is a person’s assistant or Studio’s.&lt;/p&gt;
&lt;p&gt;A Cratis Studio event model can be exported as Screenplay text, Mermaid or JSON and imported back from Screenplay with a preview. Slices can carry Given/When/Then specifications, and Play runs the model in a disposable Stage session.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;where-it-runs&quot;&gt;Where it runs&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/where-it-runs.aj_di0F__ZI5FJG.webp&quot; alt=&quot;A diagram titled Where it runs. Five steps. A merged pull request, CI, container images, Pulumi, and a Kubernetes cluster that holds Chronicle and MongoDB. A line underneath reads: From pull request to running service.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2100&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;From merged pull request to running service.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Studio runs on a managed Kubernetes cluster, built from container images, one per service. The infrastructure is code, written with &lt;a href=&quot;https://www.pulumi.com/&quot;&gt;Pulumi&lt;/a&gt; in C#.&lt;/p&gt;
&lt;p&gt;The Chronicle kernel is the public &lt;code dir=&quot;auto&quot;&gt;cratis/chronicle&lt;/code&gt; image running as a deployment, with MongoDB behind it for storage. The &lt;a href=&quot;https://blog.cratis.io/running-chronicle-in-production/&quot;&gt;running Chronicle in production&lt;/a&gt; post covers that setup, and &lt;a href=&quot;https://blog.cratis.io/personal-data-in-an-event-log/&quot;&gt;personal data in an event log&lt;/a&gt; covers how personal data is encrypted and erased. Telemetry flows out through OpenTelemetry.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;what-id-take-from-it&quot;&gt;What I’d take from it&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;You don’t need Studio’s size to use any of this. The parts that travel are small:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Make the organization a namespace.&lt;/strong&gt; If your tenant is a Chronicle namespace, each tenant’s events, observers and read models live in their own namespace.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Give each service its own event store.&lt;/strong&gt; The history of the lobby should be about invitations, and the history of Core about the product. Let facts cross the line, and decide who owns each one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Put the repeated work at the edge, keep the decisions in the service.&lt;/strong&gt; AuthProxy signs people in and finds their organization. The application decides what they can do.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Let slices be small.&lt;/strong&gt; A command, an event, a constraint and a read model fit in one file, and most of Studio is that.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want to see the result, &lt;a href=&quot;https://cratis.studio&quot;&gt;Cratis Studio&lt;/a&gt; is the place to start. The parts you can use yourself are documented at &lt;a href=&quot;https://www.cratis.io&quot;&gt;cratis.io&lt;/a&gt;: &lt;a href=&quot;https://www.cratis.io/chronicle/&quot;&gt;Chronicle&lt;/a&gt;, &lt;a href=&quot;https://www.cratis.io/arc/&quot;&gt;Arc&lt;/a&gt; and &lt;a href=&quot;https://www.cratis.io/authproxy/&quot;&gt;AuthProxy&lt;/a&gt;. Come and say hello on &lt;a href=&quot;https://discord.gg/kt4AMpV8WV&quot;&gt;Discord&lt;/a&gt; if something here made you want to know more.&lt;/p&gt;</content:encoded><category>cratis-studio</category><category>chronicle</category><category>arc</category><category>authproxy</category><category>tenancy</category><category>operations</category><category>ecosystem</category></item><item><title>Stop filtering on status</title><link>https://blog.cratis.io/stop-filtering-on-status/</link><guid isPermaLink="true">https://blog.cratis.io/stop-filtering-on-status/</guid><description>Give each stage of an entity its own read model and let Chronicle move it from one to the next. No Status column, no pile of nullable fields, nothing to index just to find the backlog. How projection variants work, model-bound and fluent.</description><pubDate>Tue, 13 Oct 2026 09:30:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/one-collection-or-two.DaPfCUIk_XzzKF.webp&quot; alt=&quot;A diagram titled One entity, one shape at a time. On the left, a card labeled WorkItem with a Status column and nullable fields. On the right, two stores joined by an arrow labeled PullRequestCreated: BacklogItem with Id and Title, then PullRequestItem with Id and PullRequestUrl. A band underneath reads Entering one variant removes the entity from the others.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1800&quot;&gt;&lt;/p&gt;
&lt;p&gt;Almost every read model starts out innocent. A work item has a title, so you add a &lt;code dir=&quot;auto&quot;&gt;Title&lt;/code&gt;. Then it needs to know whether it’s still a backlog entry or has become a pull request, so you add a &lt;code dir=&quot;auto&quot;&gt;Status&lt;/code&gt;. Then pull requests have a URL, and builds have a result, and suddenly you have a record where half the properties are nullable and every query begins with “first, filter on status, &lt;em&gt;then&lt;/em&gt; you can trust the rest”.&lt;/p&gt;
&lt;p&gt;Let’s face it, that’s the shape of the data fighting the shape of the model. A backlog entry and a pull request are different things an entity is at different times, and often they have different properties. Sometimes they hardly differ at all, and the &lt;code dir=&quot;auto&quot;&gt;Status&lt;/code&gt; filter is still the cost you pay on every query. I wrote about the declarative side of projections in &lt;a href=&quot;https://blog.cratis.io/keep-the-projection-out-of-the-model/&quot;&gt;&lt;em&gt;Keep the projection out of the model&lt;/em&gt;&lt;/a&gt;. This post is about a feature that works in both styles, and that I like a lot: &lt;strong&gt;variants&lt;/strong&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;tldr&quot;&gt;TL;DR&lt;/h2&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;A variant group is a set of read models for the &lt;em&gt;same&lt;/em&gt; logical entity, where the entity is in &lt;strong&gt;exactly one&lt;/strong&gt; of them at a time.&lt;/li&gt;
&lt;li&gt;Each variant has the properties its stage needs. No &lt;code dir=&quot;auto&quot;&gt;Status&lt;/code&gt;, no nullable leftovers. Stages can differ a lot or hardly at all.&lt;/li&gt;
&lt;li&gt;When an entity enters one variant, Chronicle removes it from the others. You don’t write the removal.&lt;/li&gt;
&lt;li&gt;Only the variant’s &lt;strong&gt;entering event&lt;/strong&gt; can create it. Any other event it listens to can only update an instance that already exists, so a late or replayed event can’t resurrect something that has moved on.&lt;/li&gt;
&lt;li&gt;It works with model-bound attributes and with the fluent builder. The fluent one has no equivalent of &lt;code dir=&quot;auto&quot;&gt;[GlobalFor&amp;#x3C;T&gt;]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Each variant is its own collection or table, and nothing queries across the group for you.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;one-entity-several-shapes&quot;&gt;One entity, several shapes&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The documentation uses a work item that is a backlog entry until a pull request exists for it, and then a pull request. Modeled as one read model, you get the &lt;code dir=&quot;auto&quot;&gt;Status&lt;/code&gt; problem from the intro. With variants, you declare one read model per stage instead.&lt;/p&gt;
&lt;p&gt;Two things make that work. First, every variant points at the same &lt;em&gt;identity type&lt;/em&gt;, which is what ties them into a group. Second, each variant names the event that &lt;strong&gt;enters&lt;/strong&gt; it. Here it is with model-bound attributes. As in the last post, the tabs are synced, so pick your language once.&lt;/p&gt;
&lt;starlight-tabs data-sync-key=&quot;language&quot;&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-0&quot; id=&quot;tab-0-0&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-1&quot; id=&quot;tab-0-1&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Kotlin&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-2&quot; id=&quot;tab-0-2&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-3&quot; id=&quot;tab-0-3&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Elixir&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-4&quot; id=&quot;tab-0-4&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-0&quot; aria-labelledby=&quot;tab-0-0&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Keys&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Title&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; PullRequestUrl&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;/// &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;summary&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/// Anchors the logical identity shared by every variant. It does not need to be a&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/// read model itself, and it does not need a common CLR base type with any of the variants.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;/// &lt;/span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;summary&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;VariantOf&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EntersOn&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;property&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Key&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Title&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;VariantOf&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EntersOn&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;property&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Key&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;property&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; PullRequestUrl&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-1&quot; aria-labelledby=&quot;tab-0-1&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.events.EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.EntersOn&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.FromEvent&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.FromEventSourceId&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.SetFrom&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.VariantOf&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.readModels.ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; title: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; pullRequestUrl: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* Anchors the logical identity shared by every variant. It does not need to be a read model&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* itself, and it does not need a common supertype with any of the variants.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@VariantOf&lt;/span&gt;&lt;span&gt;(WorkItem::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;, key &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;id&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EntersOn&lt;/span&gt;&lt;span&gt;(IssueCreated::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@FromEvent&lt;/span&gt;&lt;span&gt;(IssueCreated::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;@FromEventSourceId&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; id: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;@SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;title&quot;&lt;/span&gt;&lt;span&gt;, IssueCreated::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; title: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@VariantOf&lt;/span&gt;&lt;span&gt;(WorkItem::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;, key &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;id&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EntersOn&lt;/span&gt;&lt;span&gt;(PullRequestCreated::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@FromEvent&lt;/span&gt;&lt;span&gt;(PullRequestCreated::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;@FromEventSourceId&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; id: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;@SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;pullRequestUrl&quot;&lt;/span&gt;&lt;span&gt;, PullRequestCreated::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; pullRequestUrl: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-2&quot; aria-labelledby=&quot;tab-0-2&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EntersOn&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;FromEvent&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;FromEventSourceId&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;VariantOf&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;readModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; title&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; pullRequestUrl&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* Anchors the logical identity shared by every variant. It does not need to be a read model&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* itself, and it does not need a common supertype with any of the variants.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;VariantOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;identity&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EntersOn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;FromEvent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;FromEventSourceId&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;propertyPath&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;VariantOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;identity&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EntersOn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;FromEvent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;FromEventSourceId&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;propertyPath&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;pullRequestUrl&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;pullRequestUrl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-3&quot; aria-labelledby=&quot;tab-0-3&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;issue-created-v1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;pull-request-created-v1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;pull_request_url&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# Anchors the logical identity shared by every variant. It does not need to be a read model&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# itself, and it does not need a common shape with any of the variants.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;variant_of &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;enters_on &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;event_source_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;pull_request_url&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;variant_of &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;enters_on &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;event_source_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;pull_request_url&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;pull_request_url&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-4&quot; aria-labelledby=&quot;tab-0-4&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;entersOn&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;fromEvent&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;setFrom&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;variantOf&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/chronicle&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;pullRequestUrl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* Anchors the logical identity shared by every variant. It does not need to be a read model&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* itself, and it does not need a common shape with any of the variants.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;variantOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;entersOn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;fromEvent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;setFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;variantOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;entersOn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;fromEvent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;setFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;pullRequestUrl&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;pullRequestUrl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;starlight-tabs-restore&gt;&lt;/starlight-tabs-restore&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;WorkItem&lt;/code&gt; is only an anchor. It doesn’t have to be a read model, and it doesn’t need a common base type with the variants. Its job is to be the shared type that every variant in the group points at, which is why the docs suggest choosing one that means something on its own, rather than a marker with no purpose beyond grouping.&lt;/p&gt;
&lt;p&gt;Now follow an entity through it. When &lt;code dir=&quot;auto&quot;&gt;IssueCreated&lt;/code&gt; is processed, a &lt;code dir=&quot;auto&quot;&gt;BacklogItem&lt;/code&gt; is created, and &lt;code dir=&quot;auto&quot;&gt;Title&lt;/code&gt; maps by convention just like in any other projection. When &lt;code dir=&quot;auto&quot;&gt;PullRequestCreated&lt;/code&gt; is processed for the same entity, a &lt;code dir=&quot;auto&quot;&gt;PullRequestItem&lt;/code&gt; is created &lt;strong&gt;and the &lt;code dir=&quot;auto&quot;&gt;BacklogItem&lt;/code&gt; for that entity is removed&lt;/strong&gt;. There’s no &lt;code dir=&quot;auto&quot;&gt;RemovedWith&lt;/code&gt; anywhere. The group takes care of it. Variants aren’t required to be entered in any particular order, only to be mutually exclusive once entered, so a &lt;code dir=&quot;auto&quot;&gt;PullRequestCreated&lt;/code&gt; for an entity that was never a backlog item still creates a &lt;code dir=&quot;auto&quot;&gt;PullRequestItem&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A third variant for a later stage, say a closed work item, would be declared the same way, with its own entering event.&lt;/p&gt;
&lt;p&gt;Here is what that says in specifications. First, an issue makes a backlog item:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Keys&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Testing&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Specifications&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Xunit&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;when_an_issue_is_created&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Specification&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt; _workItemId &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;New&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReadModelScenario&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; _backlog &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Because&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_backlog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Given&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ForEventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_workItemId&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Fix the login redirect&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;should_be_in_the_backlog&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_backlog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Title&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldEqual&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Fix the login redirect&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Then a pull request for the same work item, with one &lt;code dir=&quot;auto&quot;&gt;ReadModelScenario&lt;/code&gt; per variant fed the same history:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Keys&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Testing&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Specifications&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Xunit&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;when_a_pull_request_is_created_for_a_backlog_item&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Specification&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt; _workItemId &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;New&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReadModelScenario&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; _backlog &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReadModelScenario&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; _pullRequest &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Because&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;object&lt;/span&gt;&lt;span&gt;&lt;span&gt;[]&lt;/span&gt;&lt;span&gt; history &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Fix the login redirect&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;https://example.com/pull/42&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_backlog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Given&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ForEventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_workItemId&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;history&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_pullRequest&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Given&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ForEventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_workItemId&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;history&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;should_no_longer_be_in_the_backlog&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;_backlog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ShouldBeTrue&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;should_be_a_pull_request&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_pullRequest&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PullRequestUrl&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldEqual&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;https://example.com/pull/42&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;There’s a nice property hiding in how this is built. Each variant compiles to an ordinary, independent projection definition, and the &lt;a href=&quot;https://github.com/Cratis/Chronicle/releases/tag/v19.1.0&quot;&gt;release that introduced variants&lt;/a&gt; made no kernel, wire or storage changes. So there’s nothing new to operate. A variant is a projection like any other, and the engine does the exclusion.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;only-the-entering-event-can-create-a-variant&quot;&gt;Only the entering event can create a variant&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Variants rarely listen to one event. A pull request also wants to know how its build went. You declare that exactly as you would on any projection, with &lt;code dir=&quot;auto&quot;&gt;SetFrom&lt;/code&gt; in the model-bound case. The one difference is what that mapping is allowed to do: it can update a variant that already exists, but it can never create one.&lt;/p&gt;
&lt;starlight-tabs data-sync-key=&quot;language&quot;&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-1-0&quot; id=&quot;tab-1-0&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-1-1&quot; id=&quot;tab-1-1&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Kotlin&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-1-2&quot; id=&quot;tab-1-2&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-1-3&quot; id=&quot;tab-1-3&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Elixir&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-1-4&quot; id=&quot;tab-1-4&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-1-0&quot; aria-labelledby=&quot;tab-1-0&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Keys&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; PullRequestUrl&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; BuildStatus&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;/// &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;summary&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/// BuildStatus is mapped from BuildCompleted - an event that is NOT this&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/// variant&apos;s entering event, so it is automatically reclassified into an update-only join. It can bring&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/// an already-active instance up to date, but it can never create one on its own.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;/// &lt;/span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;summary&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;VariantOf&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EntersOn&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;property&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Key&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;property&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; PullRequestUrl&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;property&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; BuildStatus&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-1-1&quot; aria-labelledby=&quot;tab-1-1&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.events.EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.EntersOn&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.FromEvent&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.FromEventSourceId&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.SetFrom&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.VariantOf&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.readModels.ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; pullRequestUrl: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; buildStatus: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* buildStatus is mapped from BuildCompleted - an event that is NOT this variant&apos;s&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* entering event, so it is automatically reclassified into an update-only join. It can bring an&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* already-active instance up to date, but it can never create one on its own.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@VariantOf&lt;/span&gt;&lt;span&gt;(WorkItem::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;, key &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;id&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EntersOn&lt;/span&gt;&lt;span&gt;(PullRequestCreated::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@FromEvent&lt;/span&gt;&lt;span&gt;(PullRequestCreated::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@FromEvent&lt;/span&gt;&lt;span&gt;(BuildCompleted::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;@FromEventSourceId&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; id: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;@SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;pullRequestUrl&quot;&lt;/span&gt;&lt;span&gt;, PullRequestCreated::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; pullRequestUrl: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;@SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;buildStatus&quot;&lt;/span&gt;&lt;span&gt;, BuildCompleted::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; buildStatus: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-1-2&quot; aria-labelledby=&quot;tab-1-2&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EntersOn&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;FromEvent&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;FromEventSourceId&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;VariantOf&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;readModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; pullRequestUrl&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; buildStatus&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* buildStatus is mapped from BuildCompleted - an event that is NOT this variant&apos;s&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* entering event, so it is automatically reclassified into an update-only join. It can bring an&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* already-active instance up to date, but it can never create one on its own.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;VariantOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;identity&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EntersOn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;FromEvent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;FromEvent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;FromEventSourceId&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;propertyPath&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;pullRequestUrl&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;pullRequestUrl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;propertyPath&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;buildStatus&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;buildStatus&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-1-3&quot; aria-labelledby=&quot;tab-1-3&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;pull-request-created-v1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;pull_request_url&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;build-completed-v1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;build_status&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# build_status is mapped from BuildCompleted - an event that is NOT this&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# variant&apos;s entering event, so it is automatically reclassified into an update-only join. It can&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# bring an already-active instance up to date, but it can never create one on its own.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.{&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;pull_request_url&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;build_status&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;variant_of &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;enters_on &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;event_source_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;pull_request_url&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;pull_request_url&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;build_status&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;build_status&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-1-4&quot; aria-labelledby=&quot;tab-1-4&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;entersOn&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;fromEvent&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;setFrom&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;variantOf&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/chronicle&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;pullRequestUrl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;buildStatus&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* buildStatus is mapped from BuildCompleted - an event that is NOT this variant&apos;s&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* entering event, so it is automatically reclassified into an update-only join. It can bring an&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* already-active instance up to date, but it can never create one on its own.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;variantOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;entersOn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;fromEvent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;fromEvent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;setFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;pullRequestUrl&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;pullRequestUrl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;setFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;buildStatus&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;buildStatus&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;starlight-tabs-restore&gt;&lt;/starlight-tabs-restore&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;BuildStatus&lt;/code&gt; is mapped from &lt;code dir=&quot;auto&quot;&gt;BuildCompleted&lt;/code&gt;, which isn’t the event named in &lt;code dir=&quot;auto&quot;&gt;EntersOn&lt;/code&gt;. Chronicle reclassifies that mapping into an update-only join on the variant’s own key before it ever reaches the projection engine. The entering event stays the only door in.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/only-the-entering-event.rzSj0NyL_FToaf.webp&quot; alt=&quot;A diagram titled Only the entering event creates a variant. Three events on the left, each with an arrow to a result. IssueCreated: BacklogItem created. PullRequestCreated: PullRequestItem created, BacklogItem removed. BuildCompleted: PullRequestItem updated, only if it already exists. A red band reads A late or replayed BuildCompleted cannot bring a variant back.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2100&quot;&gt;&lt;/p&gt;
&lt;p&gt;The docs explain why this matters, and it’s the part of the feature I find most convincing. Without that reclassification, a &lt;code dir=&quot;auto&quot;&gt;BuildCompleted&lt;/code&gt; that arrives out of order, or is replayed, could &lt;strong&gt;resurrect&lt;/strong&gt; a &lt;code dir=&quot;auto&quot;&gt;PullRequestItem&lt;/code&gt; for an entity that has since moved on to another variant, or one that was never a pull request at all. That’s exactly the bug a status column invites, and here it’s structurally impossible. You don’t have to reason about event ordering to get the guarantee. Declaring the entering event gives it to you.&lt;/p&gt;
&lt;p&gt;You can see that in specifications too. A build for something that never became a pull request creates nothing:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Keys&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Testing&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Specifications&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Xunit&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;when_a_build_completes_for_something_that_is_not_a_pull_request&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Specification&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt; _workItemId &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;New&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReadModelScenario&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; _pullRequest &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Because&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_pullRequest&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Given&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ForEventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_workItemId&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;passed&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;should_not_create_a_pull_request&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;_pullRequest&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ShouldBeTrue&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;And when the pull request exists, the build status lands on it:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Keys&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Testing&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Specifications&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Xunit&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;when_a_build_completes_after_the_pull_request_was_created&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Specification&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt; _workItemId &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;New&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReadModelScenario&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; _pullRequest &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Because&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_pullRequest&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Given&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ForEventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_workItemId&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;https://example.com/pull/42&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;passed&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;should_report_the_build_status&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_pullRequest&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BuildStatus&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldEqual&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;passed&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;So what about a build that finishes &lt;em&gt;before&lt;/em&gt; the pull request exists? The first spec says it creates nothing, and that holds. What happens once the pull request does arrive is more interesting. &lt;code dir=&quot;auto&quot;&gt;BuildStatus&lt;/code&gt; is mapped through a join, and joins are re-resolved against the last stored event of the joined stream whenever the projection handles one of the read model’s own events. So the earlier &lt;code dir=&quot;auto&quot;&gt;BuildCompleted&lt;/code&gt; is picked up the moment &lt;code dir=&quot;auto&quot;&gt;PullRequestCreated&lt;/code&gt; creates the variant:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Keys&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Testing&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Specifications&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Xunit&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;when_a_build_completes_before_the_pull_request_was_created&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Specification&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt; _workItemId &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;New&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReadModelScenario&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; _pullRequest &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Because&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_pullRequest&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Given&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ForEventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_workItemId&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;passed&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;https://example.com/pull/42&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;should_still_create_the_pull_request&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_pullRequest&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PullRequestUrl&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldEqual&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;https://example.com/pull/42&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;should_pick_up_the_build_status_reported_before_entering&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_pullRequest&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BuildStatus&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldEqual&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;passed&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If your build can really finish before the pull request exists, that’s still worth a thought about your events, but the projection won’t lose the result.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;sharing-a-mapping-across-variants&quot;&gt;Sharing a mapping across variants&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Some properties every stage wants. A title is the obvious one. Repeating the mapping on each variant gets old, so model-bound projections have &lt;code dir=&quot;auto&quot;&gt;[GlobalFor&amp;#x3C;TIdentity&gt;]&lt;/code&gt;: declare the mapping once, and it’s merged into every variant in the group. Each client spells it its own way, and the &lt;a href=&quot;https://www.cratis.io/chronicle/projections/model-bound/variants/&quot;&gt;model-bound variants page&lt;/a&gt; has all five.&lt;/p&gt;
&lt;starlight-tabs data-sync-key=&quot;language&quot;&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-2-0&quot; id=&quot;tab-2-0&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-2-1&quot; id=&quot;tab-2-1&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Kotlin&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-2-2&quot; id=&quot;tab-2-2&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-2-3&quot; id=&quot;tab-2-3&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Elixir&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-2-4&quot; id=&quot;tab-2-4&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-2-0&quot; aria-labelledby=&quot;tab-2-0&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Keys&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Title&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; PullRequestUrl&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;TitleChanged&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Title&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;VariantOf&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EntersOn&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;property&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Key&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Title&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;VariantOf&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EntersOn&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;property&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Key&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Title&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;property&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; PullRequestUrl&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;/// &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;summary&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/// Declares a mapping every variant of WorkItem shares. Every variant must have a&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/// Title member - one that does not is a declaration error, not a silently skipped mapping.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;/// &lt;/span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;summary&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;/// &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;param&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Title&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;The title every variant carrying one keeps up to date.&lt;/span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;param&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;GlobalFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SharedHandlers&lt;/span&gt;&lt;span&gt;([&lt;/span&gt;&lt;span&gt;property&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;TitleChanged&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Title&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-2-1&quot; aria-labelledby=&quot;tab-2-1&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.events.EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.EntersOn&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.FromEvent&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.FromEventSourceId&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.GlobalFor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.SetFrom&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.VariantOf&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.readModels.ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; title: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; pullRequestUrl: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;TitleChanged&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; title: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@VariantOf&lt;/span&gt;&lt;span&gt;(WorkItem::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;, key &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;id&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EntersOn&lt;/span&gt;&lt;span&gt;(IssueCreated::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@FromEvent&lt;/span&gt;&lt;span&gt;(IssueCreated::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;@FromEventSourceId&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; id: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; title: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@VariantOf&lt;/span&gt;&lt;span&gt;(WorkItem::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;, key &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;id&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EntersOn&lt;/span&gt;&lt;span&gt;(PullRequestCreated::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@FromEvent&lt;/span&gt;&lt;span&gt;(PullRequestCreated::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;@FromEventSourceId&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; id: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; title: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;@SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;pullRequestUrl&quot;&lt;/span&gt;&lt;span&gt;, PullRequestCreated::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; pullRequestUrl: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* Declares a mapping every variant of WorkItem shares. Every variant must have a&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* title member - one that does not is a declaration error, not a silently skipped mapping.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@GlobalFor&lt;/span&gt;&lt;span&gt;(WorkItem::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@FromEvent&lt;/span&gt;&lt;span&gt;(TitleChanged::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SharedHandlers&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;@SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;title&quot;&lt;/span&gt;&lt;span&gt;, TitleChanged::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; title: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-2-2&quot; aria-labelledby=&quot;tab-2-2&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EntersOn&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;FromEvent&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;FromEventSourceId&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;GlobalFor&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;VariantOf&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;readModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; title&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; pullRequestUrl&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;TitleChanged&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; title&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;VariantOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;identity&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EntersOn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;FromEvent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;FromEventSourceId&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;VariantOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;identity&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EntersOn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;FromEvent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;FromEventSourceId&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;propertyPath&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;pullRequestUrl&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;pullRequestUrl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* Declares a mapping every variant of WorkItem shares. Every variant must have a&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* title member - one that does not is a declaration error, not a silently skipped mapping.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;GlobalFor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;identity&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;FromEvent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;TitleChanged&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SharedHandlers&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;propertyPath&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;TitleChanged&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-2-3&quot; aria-labelledby=&quot;tab-2-3&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;issue-created-v1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;pull-request-created-v1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;pull_request_url&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;TitleChanged&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;title-changed-v1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;variant_of &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;enters_on &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;event_source_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;pull_request_url&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;variant_of &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;enters_on &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;event_source_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;pull_request_url&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;pull_request_url&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# Declares a mapping every variant of WorkItem shares. Every variant must have a&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# title member - one that does not is a declaration error, not a silently skipped mapping. Never&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# registered as a projection on its own.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;SharedHandlers&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;GlobalHandler&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;identity&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;TitleChanged&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;TitleChanged&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-2-4&quot; aria-labelledby=&quot;tab-2-4&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;entersOn&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;fromEvent&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;globalFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;setFrom&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;variantOf&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/chronicle&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;pullRequestUrl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;TitleChanged&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;variantOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;entersOn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;fromEvent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;variantOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;entersOn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;fromEvent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;setFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;pullRequestUrl&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;pullRequestUrl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* Declares a mapping every variant of WorkItem shares. Every variant must have a&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* title member - one that does not is a declaration error, not a silently skipped mapping. Never&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* registered as a projection on its own.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;globalFor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SharedHandlers&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;setFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;TitleChanged&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;starlight-tabs-restore&gt;&lt;/starlight-tabs-restore&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;This block is its own small example, with a fresh set of events. &lt;code dir=&quot;auto&quot;&gt;SharedHandlers&lt;/code&gt; is not a read model and no variant inherits from it. It only carries the mapping, and &lt;code dir=&quot;auto&quot;&gt;TitleChanged&lt;/code&gt; now updates the title on whichever variant the work item is in:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Keys&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Testing&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Specifications&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Xunit&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;when_the_title_changes_after_the_pull_request_was_created&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Specification&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt; _workItemId &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;New&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReadModelScenario&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; _pullRequest &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Because&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_pullRequest&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Given&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ForEventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_workItemId&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Fix login&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;https://example.com/pull/42&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;TitleChanged&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Fix the login redirect&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;should_have_the_new_title&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_pullRequest&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Title&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldEqual&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Fix the login redirect&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Like any other non-entering mapping, a shared one can only update an active variant, so it’s safe to share across stages that begin at different times. And every variant must have the member a shared mapping targets. A variant without it is a declaration error, caught when the projection is discovered, not an unpredictable surprise when a shared event finally shows up.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-same-thing-fluent&quot;&gt;The same thing, fluent&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Everything above is also available in the declarative style, and this is where the two styles from the last post line up one to one.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/two-spellings.Cbc1ZL40_ZqNliY.webp&quot; alt=&quot;A diagram titled Same group, two spellings. Model-bound column: VariantOf of T, EntersOn of E, SetFrom of E, GlobalFor of T. Fluent column: .VariantOf of T with a key lambda, .EntersOn of E, .From of E, and Repeat .From of E on each variant for the one that has no equivalent. A band reads Both build the same mutually exclusive group.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1900&quot;&gt;&lt;/p&gt;
&lt;p&gt;The read models are plain records, the projections say which group and which entering event, and the identity type is declared exactly as before.&lt;/p&gt;
&lt;starlight-tabs data-sync-key=&quot;language&quot;&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-3-0&quot; id=&quot;tab-3-0&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-3-1&quot; id=&quot;tab-3-1&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Kotlin&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-3-2&quot; id=&quot;tab-3-2&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-3-3&quot; id=&quot;tab-3-3&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Elixir&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-3-4&quot; id=&quot;tab-3-4&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-3-0&quot; aria-labelledby=&quot;tab-3-0&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Title&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; PullRequestUrl&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;/// &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;summary&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/// Anchors the logical identity shared by BacklogItem and PullRequestItem.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/// Deliberately not a read model itself, and does not need a common CLR base type with either variant.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;/// &lt;/span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;summary&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Title&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; PullRequestUrl&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BacklogItemProjection&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Define&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; builder&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;VariantOf&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Id&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EntersOn&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItemProjection&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Define&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; builder&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;VariantOf&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Id&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EntersOn&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-3-1&quot; aria-labelledby=&quot;tab-3-1&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.events.EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.IProjectionBuilderFor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.IProjectionFor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; title: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; pullRequestUrl: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* Anchors the logical identity shared by BacklogItem and PullRequestItem.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* Deliberately not a read model itself, and does not need a common supertype with either variant.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; id: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; title: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; id: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; pullRequestUrl: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BacklogItemProjection&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;override&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;define&lt;/span&gt;&lt;span&gt;(builder: &lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;variantOf&lt;/span&gt;&lt;span&gt;(WorkItem::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;, BacklogItem::&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;entersOn&lt;/span&gt;&lt;span&gt;(IssueCreated::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItemProjection&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;override&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;define&lt;/span&gt;&lt;span&gt;(builder: &lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;variantOf&lt;/span&gt;&lt;span&gt;(WorkItem::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;, PullRequestItem::&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;entersOn&lt;/span&gt;&lt;span&gt;(PullRequestCreated::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-3-2&quot; aria-labelledby=&quot;tab-3-2&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; title&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; pullRequestUrl&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* Anchors the logical identity shared by BacklogItem and PullRequestItem.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* Deliberately not a read model itself, and does not need a common supertype with either variant.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;pullRequestUrl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BacklogItemProjection&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;implements&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Override&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;define&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;variantOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;entersOn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItemProjection&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;implements&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Override&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;define&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;variantOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;entersOn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-3-3&quot; aria-labelledby=&quot;tab-3-3&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;dec-variant-issue-created-v1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;dec-variant-pull-request-created-v1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;pull_request_url&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# Anchors the logical identity shared by BacklogItem and PullRequestItem.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# Deliberately not a read model itself, and does not need a common shape with either variant.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;pull_request_url&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BacklogItemProjection&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projection&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;model&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;variant_of &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;enters_on &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;event_source_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PullRequestItemProjection&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projection&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;model&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;variant_of &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;enters_on &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;event_source_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;pull_request_url&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;pull_request_url&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-3-4&quot; aria-labelledby=&quot;tab-3-4&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/chronicle&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;projection&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/chronicle&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;pullRequestUrl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* Anchors the logical identity shared by BacklogItem and PullRequestItem.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* Deliberately not a read model itself, and does not need a common shape with either variant.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;pullRequestUrl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;projection&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BacklogItemProjection&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;implements&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;define&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BacklogItem&lt;/span&gt;&lt;span&gt;&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;variantOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;entersOn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IssueCreated&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;projection&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItemProjection&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;implements&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;define&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;variantOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;entersOn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;starlight-tabs-restore&gt;&lt;/starlight-tabs-restore&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;VariantOf&lt;/code&gt; takes the identity type and a key accessor, and &lt;code dir=&quot;auto&quot;&gt;EntersOn&lt;/code&gt; names the entering event. Auto-mapping is on as in any fluent projection, so &lt;code dir=&quot;auto&quot;&gt;Title&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;PullRequestUrl&lt;/code&gt; map by name without a &lt;code dir=&quot;auto&quot;&gt;Set&lt;/code&gt;. Entering &lt;code dir=&quot;auto&quot;&gt;PullRequestItem&lt;/code&gt; removes the &lt;code dir=&quot;auto&quot;&gt;BacklogItem&lt;/code&gt;, again with no removal call, because the group is cross-wired automatically once every variant in it has been discovered.&lt;/p&gt;
&lt;p&gt;An additional event is an ordinary &lt;code dir=&quot;auto&quot;&gt;From&lt;/code&gt;, and it gets the same reclassification as &lt;code dir=&quot;auto&quot;&gt;SetFrom&lt;/code&gt; did:&lt;/p&gt;
&lt;starlight-tabs data-sync-key=&quot;language&quot;&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-4-0&quot; id=&quot;tab-4-0&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-4-1&quot; id=&quot;tab-4-1&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Kotlin&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-4-2&quot; id=&quot;tab-4-2&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-4-3&quot; id=&quot;tab-4-3&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Elixir&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-4-4&quot; id=&quot;tab-4-4&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-4-0&quot; aria-labelledby=&quot;tab-4-0&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; PullRequestUrl&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; BuildStatus&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; PullRequestUrl&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; BuildStatus&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;/// &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;summary&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/// From&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x26;&lt;/span&gt;&lt;span&gt;lt&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;#x26;&lt;/span&gt;&lt;span&gt;gt&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span&gt; is declared exactly like an ordinary multi-event&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/// projection. Because that event is NOT the one named with EntersOn, the builder automatically&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/// reclassifies it into an update-only join on the variant&apos;s own key when the definition is built - it&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/// can bring an already-active instance up to date, but it can never create one on its own.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;/// &lt;/span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;summary&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItemProjection&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Define&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; builder&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;VariantOf&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Id&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EntersOn&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;From&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-4-1&quot; aria-labelledby=&quot;tab-4-1&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.events.EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.IProjectionBuilderFor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.IProjectionFor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; pullRequestUrl: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; buildStatus: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; id: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; pullRequestUrl: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; buildStatus: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* from(BuildCompleted::class) is declared exactly like an ordinary multi-event&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* projection. Because that event is NOT the one named with entersOn, the builder automatically&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* reclassifies it into an update-only join on the variant&apos;s own key when the definition is built -&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* it can bring an already-active instance up to date, but it can never create one on its own.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItemProjection&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;override&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;define&lt;/span&gt;&lt;span&gt;(builder: &lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;variantOf&lt;/span&gt;&lt;span&gt;(WorkItem::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;, PullRequestItem::&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;entersOn&lt;/span&gt;&lt;span&gt;(PullRequestCreated::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;(BuildCompleted::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-4-2&quot; aria-labelledby=&quot;tab-4-2&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; pullRequestUrl&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; buildStatus&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;pullRequestUrl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;buildStatus&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* from(BuildCompleted.class) is declared exactly like an ordinary multi-event&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* projection. Because that event is NOT the one named with entersOn, the builder automatically&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* reclassifies it into an update-only join on the variant&apos;s own key when the definition is built -&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* it can bring an already-active instance up to date, but it can never create one on its own.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItemProjection&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;implements&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Override&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;define&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;variantOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;entersOn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-4-3&quot; aria-labelledby=&quot;tab-4-3&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;dec-variant-updating-pull-request-created-v1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;pull_request_url&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;dec-variant-updating-build-completed-v1&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;build_status&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;pull_request_url&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;build_status&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# `from BuildCompleted` is declared exactly like an ordinary multi-event&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# projection. Because that event is NOT the one named with enters_on, it is automatically&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# reclassified into an update-only join on the variant&apos;s own key when the definition is built -&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# it can bring an already-active instance up to date, but it can never create one on its own.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PullRequestItemProjection&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projection&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;model&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.{&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;variant_of &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;enters_on &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;event_source_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;pull_request_url&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;pull_request_url&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;build_status&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;build_status&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-4-4&quot; aria-labelledby=&quot;tab-4-4&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;projection&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/chronicle&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;pullRequestUrl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;buildStatus&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;pullRequestUrl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;buildStatus&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* .from(BuildCompleted) is declared exactly like an ordinary multi-event&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* projection. Because that event is NOT the one named with entersOn, the builder automatically&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* reclassifies it into an update-only join on the variant&apos;s own key when the definition is built -&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;* it can bring an already-active instance up to date, but it can never create one on its own.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;*/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;projection&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;PullRequestItemProjection&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;implements&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;define&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;PullRequestItem&lt;/span&gt;&lt;span&gt;&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;variantOf&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;WorkItem&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;entersOn&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;PullRequestCreated&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BuildCompleted&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;starlight-tabs-restore&gt;&lt;/starlight-tabs-restore&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;From&amp;#x3C;BuildCompleted&gt;()&lt;/code&gt; looks like any other subscription. Because it isn’t the entering event, the builder turns it into an update-only join keyed on the same property &lt;code dir=&quot;auto&quot;&gt;VariantOf&lt;/code&gt; named, before the definition reaches the engine. Same guarantee, spelled differently.&lt;/p&gt;
&lt;p&gt;The one real difference is sharing. Fluent projections have no equivalent of &lt;code dir=&quot;auto&quot;&gt;[GlobalFor&amp;#x3C;T&gt;]&lt;/code&gt;. Each projection is its own class with its own definition, so a mapping every variant needs is a &lt;code dir=&quot;auto&quot;&gt;.From&amp;#x3C;TEvent&gt;()&lt;/code&gt; on each builder. The docs’ own advice is that if you end up repeating one often enough for it to hurt, that repetition is a reason to use model-bound variants for that group.&lt;/p&gt;
&lt;p&gt;The first specification in this post, with the same history and the same assertions against &lt;code dir=&quot;auto&quot;&gt;FluentBacklogItem&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;FluentPullRequestItem&lt;/code&gt;, passes for the fluent version too. A &lt;code dir=&quot;auto&quot;&gt;ReadModelScenario&lt;/code&gt; discovers the other variants of the group, model-bound or fluent, so entering one variant removes the entity from the others there as it does on a server.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;what-it-costs&quot;&gt;What it costs&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Be honest with yourself about the trade, because there is one.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Each variant is its own collection.&lt;/strong&gt; There’s no built-in query that spans the group. If a caller needs “this entity, whichever stage it’s in”, it asks each variant explicitly. That’s by design, and it’s also something you have to build.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The shapes don’t have to differ.&lt;/strong&gt; Variants fit entities whose stages really are different things, but they fit just as well when the stages share nearly the same shape. In Direct, the journey information shown for an item is much the same across stages, and that is by design: each stage is its own collection, so a query reads only that stage and there’s no &lt;code dir=&quot;auto&quot;&gt;Status&lt;/code&gt; to filter on or index. Both uses are valid and they aren’t mutually exclusive.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It’s a projection feature.&lt;/strong&gt; Variants are declared on model-bound and fluent projections. A reducer builds the state of one read model, so it’s not where this lives. If you’re deciding between a projection and a reducer, the previous post and &lt;a href=&quot;https://blog.cratis.io/from-event-to-read-model/#when-attributes-cant-say-it-reducers&quot;&gt;&lt;em&gt;From event to read model&lt;/em&gt;&lt;/a&gt; cover the difference.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And what do you get for it? The fastest thing that can possibly work, as I like to put it. A query for the backlog reads the backlog. There’s no &lt;code dir=&quot;auto&quot;&gt;Status&lt;/code&gt; to filter on, so there’s none to index just to keep that lookup quick, and the rows you don’t want aren’t in the way. That’s the design bet. I haven’t benchmarked it for this post, so don’t take it as a number. Take it as the reason the shape exists.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The next time you reach for a &lt;code dir=&quot;auto&quot;&gt;Status&lt;/code&gt; column, ask whether each stage deserves its own read model, either because it’s a different thing or because you’d rather not filter on status for every query. If so, give it its own read model, name the event that makes an entity become it, and let Chronicle do the moving. That’s a few attributes, or a few builder calls, and a status filter you never write.&lt;/p&gt;
&lt;p&gt;The full reference is in the docs, for both &lt;a href=&quot;https://www.cratis.io/chronicle/projections/model-bound/variants/&quot;&gt;model-bound variants&lt;/a&gt; and &lt;a href=&quot;https://www.cratis.io/chronicle/projections/declarative/variants/&quot;&gt;fluent variants&lt;/a&gt;, and the &lt;a href=&quot;https://www.cratis.io/chronicle/projections/choosing-a-read-model-style/&quot;&gt;guide to choosing a read-model style&lt;/a&gt; is a good companion if you’re still deciding between the ways to build one. How a read model gets queried afterwards, and how a live list learns about changes, is in &lt;a href=&quot;https://blog.cratis.io/from-event-to-read-model/&quot;&gt;&lt;em&gt;From event to read model&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Variants need Chronicle 19.1.0 or later, and the scenario behavior described here needs 19.57.1 or later.&lt;/em&gt;&lt;/p&gt;</content:encoded><category>chronicle</category><category>event-sourcing</category></item><item><title>Keep the projection out of the model</title><link>https://blog.cratis.io/keep-the-projection-out-of-the-model/</link><guid isPermaLink="true">https://blog.cratis.io/keep-the-projection-out-of-the-model/</guid><description>Model-bound projections put the mapping on the read model. Fluent projections keep it beside the model, in IProjectionFor&amp;lt;T&amp;gt;. Same engine, a different trade-off, and how both differ from a reducer.</description><pubDate>Tue, 13 Oct 2026 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/two-places-one-definition.6rsF_pt0_ZyPJXI.webp&quot; alt=&quot;A diagram titled Where the mapping lives. Two columns. Model-bound, attributes on the model, is one file, Order.cs, labeled Model plus mapping together. Fluent, IProjectionFor of T, is two files, Order.cs and OrderProjection.cs, labeled Plain record plus mapping. Both columns point to a band that reads Same projection engine, same read model.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1900&quot;&gt;&lt;/p&gt;
&lt;p&gt;Model-bound projections get most of the attention, and I get it. You put an attribute on a property, the read model says where its data comes from, and there’s nothing else to go looking for. That cohesion is a big part of why it’s where we tell people to start.&lt;/p&gt;
&lt;p&gt;But it wasn’t the first thing we built. The fluent, declarative &lt;code dir=&quot;auto&quot;&gt;IProjectionFor&amp;#x3C;T&gt;&lt;/code&gt; was. And to be honest, I think it gets undersold now. The trade-off model-bound makes is real: everything ends up in the same place. The read model, the events it listens to, the keys, the children, the removals. For a small read model that’s lovely. For a bigger one it turns into a pile of attributes that a human has to decode, and let’s face it, a projection gets read a lot more often than it gets written.&lt;/p&gt;
&lt;p&gt;So this post is about the other option: what it is, when it earns its keep, and how it differs from the thing people most often confuse it with, the reducer.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;tldr&quot;&gt;TL;DR&lt;/h2&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Model-bound and fluent are two ways to write the same kind of projection. Chronicle stores a projection definition either way and its projection engine runs it.&lt;/li&gt;
&lt;li&gt;Model-bound gives you &lt;strong&gt;cohesion&lt;/strong&gt;. Fluent gives you &lt;strong&gt;separation&lt;/strong&gt;: a plain read model and a mapping you can read on its own.&lt;/li&gt;
&lt;li&gt;In Kotlin and Java, fluent is also the way to express a mapping the annotations can’t, such as toggling a flag per event type.&lt;/li&gt;
&lt;li&gt;A reducer is not a third spelling of the same idea. It’s your code, running in your application, that takes an event and the current state and returns the next state.&lt;/li&gt;
&lt;li&gt;Start with model-bound. Reach for fluent when the attributes stop being readable or you want a read model without Chronicle attributes on it. Reach for a reducer when the logic reads better as code.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;two-places-for-the-same-mapping&quot;&gt;Two places for the same mapping&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Every projection answers the same question: given these &lt;a href=&quot;https://blog.cratis.io/events-are-facts/&quot;&gt;events&lt;/a&gt;, what does the read model look like? The two styles only disagree on where you write the answer.&lt;/p&gt;
&lt;p&gt;With &lt;a href=&quot;https://www.cratis.io/chronicle/projections/model-bound/&quot;&gt;model-bound projections&lt;/a&gt; the answer is attributes on the read model itself. With &lt;a href=&quot;https://www.cratis.io/chronicle/projections/declarative/&quot;&gt;declarative projections&lt;/a&gt; the read model is an ordinary type, and a separate class implementing &lt;code dir=&quot;auto&quot;&gt;IProjectionFor&amp;#x3C;TReadModel&gt;&lt;/code&gt; uses a builder to say how events map onto it.&lt;/p&gt;
&lt;p&gt;What happens next is identical. &lt;a href=&quot;https://blog.cratis.io/from-event-to-read-model/&quot;&gt;&lt;em&gt;From event to read model&lt;/em&gt;&lt;/a&gt; walks through how all the ways of writing a projection converge: the client turns what you wrote into a projection definition, the kernel stores it, and the projection engine applies it to events and writes the result to the sink. The engine never knows which style you picked. Which means the choice is about &lt;em&gt;you&lt;/em&gt;, and the people who’ll read this code later.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-same-book-both-ways&quot;&gt;The same book, both ways&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Chronicle’s documentation has a deliberately small example in its &lt;a href=&quot;https://www.cratis.io/chronicle/projections/choosing-a-read-model-style/&quot;&gt;guide to choosing a read-model style&lt;/a&gt;: a book is registered, borrowed and returned. These are the three events. The tabs on this page stay in sync, so pick your language once.&lt;/p&gt;
&lt;starlight-tabs data-sync-key=&quot;language&quot;&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-0&quot; id=&quot;tab-0-0&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-1&quot; id=&quot;tab-0-1&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Kotlin&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-2&quot; id=&quot;tab-0-2&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-3&quot; id=&quot;tab-0-3&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Elixir&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-0-4&quot; id=&quot;tab-0-4&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-0&quot; aria-labelledby=&quot;tab-0-0&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Title&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Isbn&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; MemberName&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-1&quot; aria-labelledby=&quot;tab-0-1&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.events.EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; title: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; isbn: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; memberName: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-2&quot; aria-labelledby=&quot;tab-0-2&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; title&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; isbn&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; memberName&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-3&quot; aria-labelledby=&quot;tab-0-3&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;choosing-style-book-registered&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;choosing-style-book-borrowed&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;member_name&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;choosing-style-book-returned&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-0-4&quot; aria-labelledby=&quot;tab-0-4&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/chronicle&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;memberName&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;starlight-tabs-restore&gt;&lt;/starlight-tabs-restore&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;First the model-bound version. The mapping lives on the properties:&lt;/p&gt;
&lt;starlight-tabs data-sync-key=&quot;language&quot;&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-1-0&quot; id=&quot;tab-1-0&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-1-1&quot; id=&quot;tab-1-1&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Kotlin&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-1-2&quot; id=&quot;tab-1-2&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-1-3&quot; id=&quot;tab-1-3&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Elixir&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-1-4&quot; id=&quot;tab-1-4&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-1-0&quot; aria-labelledby=&quot;tab-1-0&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Keys&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusModelBound&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Key&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Title&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;SetValue&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;SetValue&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;bool&lt;/span&gt;&lt;span&gt;&lt;span&gt; IsBorrowed&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;nameof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;MemberName&lt;/span&gt;&lt;span&gt;))]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;SetValue&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;// null! - SetValue&apos;s constructor takes non-nullable object&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; BorrowedBy&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-1-1&quot; aria-labelledby=&quot;tab-1-1&quot; role=&quot;tabpanel&quot; tabindex=&quot;0&quot; hidden&gt;&lt;blockquote&gt;
&lt;p&gt;Kotlin does not support this workflow yet.
The model-bound &lt;code dir=&quot;auto&quot;&gt;@SetFrom&lt;/code&gt; annotation maps a property from an event, but there is
no equivalent to C#’s &lt;code dir=&quot;auto&quot;&gt;[SetValue&amp;#x3C;TEvent&gt;(...)]&lt;/code&gt; for assigning a constant value —
so a flag like &lt;code dir=&quot;auto&quot;&gt;isBorrowed&lt;/code&gt; cannot be toggled per event type through model-bound
attributes alone. Track the client SDK issue, or use a reducer instead.&lt;/p&gt;
&lt;/blockquote&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-1-2&quot; aria-labelledby=&quot;tab-1-2&quot; role=&quot;tabpanel&quot; tabindex=&quot;0&quot; hidden&gt;&lt;blockquote&gt;
&lt;p&gt;Java does not support this workflow yet.
The model-bound &lt;code dir=&quot;auto&quot;&gt;@SetFrom&lt;/code&gt; annotation maps a property from an event, but there is
no equivalent to C#’s &lt;code dir=&quot;auto&quot;&gt;[SetValue&amp;#x3C;TEvent&gt;(...)]&lt;/code&gt; for assigning a constant value —
so a flag like &lt;code dir=&quot;auto&quot;&gt;isBorrowed&lt;/code&gt; cannot be toggled per event type through model-bound
attributes alone. Track the client SDK issue, or use a reducer instead.&lt;/p&gt;
&lt;/blockquote&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-1-3&quot; aria-labelledby=&quot;tab-1-3&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BookStatusModelBound&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;is_borrowed&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;borrowed_by&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nil&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;event_source_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;is_borrowed&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;borrowed_by&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nil&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;is_borrowed&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;borrowed_by&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;member_name&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;is_borrowed&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;borrowed_by&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nil&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-1-4&quot; aria-labelledby=&quot;tab-1-4&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;setFrom&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;setValue&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/chronicle&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;field&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/fundamentals&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusModelBound&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;setFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;setFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;setValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;setValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;isBorrowed&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;setFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;memberName&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;setValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;field&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;borrowedBy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;starlight-tabs-restore&gt;&lt;/starlight-tabs-restore&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;Then the fluent version. The read model has no mapping on it at all, and a projection class says what each event does:&lt;/p&gt;
&lt;starlight-tabs data-sync-key=&quot;language&quot;&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-2-0&quot; id=&quot;tab-2-0&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-2-1&quot; id=&quot;tab-2-1&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Kotlin&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-2-2&quot; id=&quot;tab-2-2&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-2-3&quot; id=&quot;tab-2-3&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Elixir&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-2-4&quot; id=&quot;tab-2-4&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-2-0&quot; aria-labelledby=&quot;tab-2-0&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusFluent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Title&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;bool&lt;/span&gt;&lt;span&gt;&lt;span&gt; IsBorrowed&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; BorrowedBy&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusProjection&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookStatusFluent&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Define&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookStatusFluent&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; builder&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;From&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Set&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Id&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ToEventSourceId&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Set&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IsBorrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ToValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Clear&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BorrowedBy&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;From&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Set&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IsBorrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ToValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Set&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BorrowedBy&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;To&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;MemberName&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;From&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Set&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IsBorrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ToValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Clear&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BorrowedBy&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-2-1&quot; aria-labelledby=&quot;tab-2-1&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// Requires io.cratis:chronicle 6.5.0 or later.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.IProjectionBuilderFor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.IProjectionFor&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatus&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; id: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; title: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; isbn: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; isBorrowed: &lt;/span&gt;&lt;span&gt;Boolean&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; borrowedBy: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;? &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusProjection&lt;/span&gt;&lt;span&gt; : &lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookStatus&lt;/span&gt;&lt;span&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;override&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;define&lt;/span&gt;&lt;span&gt;(builder: &lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookStatus&lt;/span&gt;&lt;span&gt;&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;(BookRegistered::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;it.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(BookStatus::&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;toEventSourceId&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;it.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(BookStatus::&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;toProperty&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;title&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;it.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(BookStatus::&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;toProperty&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;isbn&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;it.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(BookStatus::&lt;/span&gt;&lt;span&gt;isBorrowed&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;toValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;it.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(BookStatus::&lt;/span&gt;&lt;span&gt;borrowedBy&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;toValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;(BookBorrowed::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;it.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(BookStatus::&lt;/span&gt;&lt;span&gt;isBorrowed&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;toValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;it.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(BookStatus::&lt;/span&gt;&lt;span&gt;borrowedBy&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;toProperty&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;memberName&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;(BookReturned::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;it.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(BookStatus::&lt;/span&gt;&lt;span&gt;isBorrowed&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;toValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;it.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(BookStatus::&lt;/span&gt;&lt;span&gt;borrowedBy&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;span&gt;toValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-2-2&quot; aria-labelledby=&quot;tab-2-2&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// Requires io.cratis:chronicle 6.5.0 or later.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatus&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;boolean&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;isBorrowed&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;borrowedBy&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusProjection&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;implements&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookStatus&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Override&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;define&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookStatus&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; fb &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;fb&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;toEventSourceId&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;fb&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;toProperty&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;fb&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;toProperty&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;fb&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Boolean&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;isBorrowed&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;toValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;fb&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;borrowedBy&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;toValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; fb &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;fb&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Boolean&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;isBorrowed&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;toValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;fb&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;borrowedBy&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;toProperty&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;memberName&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; fb &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;fb&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Boolean&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;isBorrowed&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;toValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;fb&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;borrowedBy&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;toValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-2-3&quot; aria-labelledby=&quot;tab-2-3&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BookStatusFluent&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;is_borrowed&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;borrowed_by&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nil&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BookStatusProjection&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projection&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;model&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BookStatusFluent&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;event_source_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;is_borrowed&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;borrowed_by&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nil&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;is_borrowed&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;borrowed_by&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;member_name&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;is_borrowed&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;borrowed_by&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nil&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-2-4&quot; aria-labelledby=&quot;tab-2-4&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;projection&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/chronicle&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusFluent&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;isBorrowed&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;borrowedBy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;projection&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusProjection&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;implements&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookStatusFluent&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;define&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookStatusFluent&lt;/span&gt;&lt;span&gt;&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;toEventSourceId&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isBorrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;toValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;borrowedBy&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;toValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isBorrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;toValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;borrowedBy&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;memberName&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isBorrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;toValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;borrowedBy&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;toValue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;starlight-tabs-restore&gt;&lt;/starlight-tabs-restore&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;Same events, same documents come out. Read the two next to each other and notice where your eyes go. In the model-bound version you read the model and learn the mapping as a side effect. In the fluent version you read one event at a time: &lt;em&gt;when a book is borrowed, set &lt;code dir=&quot;auto&quot;&gt;IsBorrowed&lt;/code&gt; to true and &lt;code dir=&quot;auto&quot;&gt;BorrowedBy&lt;/code&gt; to the member&lt;/em&gt;. It’s a bit more code, and for this tiny model I’d happily take the attributes.&lt;/p&gt;
&lt;p&gt;Now look at the Kotlin and Java tabs of the model-bound example. That’s not me skipping something. Chronicle’s docs say the model-bound &lt;code dir=&quot;auto&quot;&gt;@SetFrom&lt;/code&gt; annotation has no equivalent to C#’s &lt;code dir=&quot;auto&quot;&gt;[SetValue&amp;#x3C;TEvent&gt;(...)]&lt;/code&gt;, so a flag like &lt;code dir=&quot;auto&quot;&gt;isBorrowed&lt;/code&gt; can’t be toggled per event type through annotations alone. The note in the docs suggests tracking the client SDK issue or using a reducer instead, and the fluent example on the same page does it with &lt;code dir=&quot;auto&quot;&gt;toValue(true)&lt;/code&gt;. So in those clients, fluent isn’t just a matter of taste.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;when-the-attributes-pile-up&quot;&gt;When the attributes pile up&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The book is a gentle example. Here is one where the attributes start to hurt: an order with line items that get added, adjusted and removed. This is the model-bound version, adapted from the &lt;a href=&quot;https://www.cratis.io/chronicle/projections/model-bound/children/&quot;&gt;children documentation&lt;/a&gt;.&lt;/p&gt;
&lt;starlight-tabs data-sync-key=&quot;language&quot;&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-3-0&quot; id=&quot;tab-3-0&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-3-1&quot; id=&quot;tab-3-1&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Kotlin&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-3-2&quot; id=&quot;tab-3-2&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-3-3&quot; id=&quot;tab-3-3&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Elixir&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-3-4&quot; id=&quot;tab-3-4&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-3-0&quot; aria-labelledby=&quot;tab-3-0&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Keys&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ModelBound&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; CustomerName&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; ItemId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; ProductName&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; InitialQuantity&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;decimal&lt;/span&gt;&lt;span&gt;&lt;span&gt; UnitPrice&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;QuantityAdjusted&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; ItemId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; NewQuantity&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LineItemRemoved&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; ItemId&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Order&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Key&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;OrderCreated&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;nameof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;OrderCreated&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;CustomerName&lt;/span&gt;&lt;span&gt;))]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Customer&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;ChildrenFrom&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nameof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ItemId&lt;/span&gt;&lt;span&gt;))]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;RemovedWith&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;LineItemRemoved&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nameof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LineItemRemoved&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ItemId&lt;/span&gt;&lt;span&gt;))]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;IEnumerable&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;OrderLine&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; Lines&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;FromEvent&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;QuantityAdjusted&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nameof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QuantityAdjusted&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ItemId&lt;/span&gt;&lt;span&gt;))]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderLine&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Key&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;nameof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ProductName&lt;/span&gt;&lt;span&gt;))]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Product&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;nameof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;InitialQuantity&lt;/span&gt;&lt;span&gt;))]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;QuantityAdjusted&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;nameof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QuantityAdjusted&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;NewQuantity&lt;/span&gt;&lt;span&gt;))]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Quantity&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;nameof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;UnitPrice&lt;/span&gt;&lt;span&gt;))]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;decimal&lt;/span&gt;&lt;span&gt;&lt;span&gt; UnitPrice&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-3-1&quot; aria-labelledby=&quot;tab-3-1&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.events.EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.ChildrenFrom&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.FromEvent&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.RemovedWith&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.projections.SetFrom&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.readModels.ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// Events&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; customerName: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; itemId: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; productName: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; initialQuantity: &lt;/span&gt;&lt;span&gt;Int&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; unitPrice: &lt;/span&gt;&lt;span&gt;Double&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;QuantityAdjusted&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; itemId: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; newQuantity: &lt;/span&gt;&lt;span&gt;Int&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LineItemRemoved&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; itemId: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// Read Models&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@FromEvent&lt;/span&gt;&lt;span&gt;(OrderCreated::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Order&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;@SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;customerName&quot;&lt;/span&gt;&lt;span&gt;, OrderCreated::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; customer: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;@ChildrenFrom&lt;/span&gt;&lt;span&gt;(LineItemAdded::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;, key &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;itemId&quot;&lt;/span&gt;&lt;span&gt;, identifiedBy &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;itemId&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;@ChildrenFrom&lt;/span&gt;&lt;span&gt;(QuantityAdjusted::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;, key &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;itemId&quot;&lt;/span&gt;&lt;span&gt;, identifiedBy &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;itemId&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;@RemovedWith&lt;/span&gt;&lt;span&gt;(LineItemRemoved::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;, key &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;itemId&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; lines: &lt;/span&gt;&lt;span&gt;List&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;OrderLine&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;emptyList&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderLine&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; itemId: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;@SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;productName&quot;&lt;/span&gt;&lt;span&gt;, LineItemAdded::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; product: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;@SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;initialQuantity&quot;&lt;/span&gt;&lt;span&gt;, LineItemAdded::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;@SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;newQuantity&quot;&lt;/span&gt;&lt;span&gt;, QuantityAdjusted::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; quantity: &lt;/span&gt;&lt;span&gt;Int&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;@SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;unitPrice&quot;&lt;/span&gt;&lt;span&gt;, LineItemAdded::&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; unitPrice: &lt;/span&gt;&lt;span&gt;Double&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-3-2&quot; aria-labelledby=&quot;tab-3-2&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ChildrenFrom&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;FromEvent&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;RemovedWith&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;readModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;java&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;util&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Collections&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;java&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;util&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;List&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// Events&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; customerName&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; itemId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; productName&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; initialQuantity&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;double&lt;/span&gt;&lt;span&gt;&lt;span&gt; unitPrice&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;QuantityAdjusted&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; itemId&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; newQuantity&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LineItemRemoved&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; itemId&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// Read Models&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;FromEvent&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderCreated&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Order&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;propertyPath&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;customerName&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderCreated&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;customer&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;ChildrenFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;itemId&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;identifiedBy&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;itemId&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;ChildrenFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;QuantityAdjusted&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;itemId&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;identifiedBy&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;itemId&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;RemovedWith&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LineItemRemoved&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;itemId&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;List&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;OrderLine&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;lines&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Collections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;emptyList&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderLine&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;itemId&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;propertyPath&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;productName&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;product&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;propertyPath&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;initialQuantity&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;propertyPath&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;newQuantity&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;QuantityAdjusted&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;SetFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;propertyPath&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;unitPrice&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;double&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;unitPrice&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0.0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-3-3&quot; aria-labelledby=&quot;tab-3-3&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OrderCreated&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;order-created&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;customer_name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;line-item-added&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;item_id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;product_name&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;initial_quantity&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;unit_price&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;QuantityAdjusted&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;quantity-adjusted&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;item_id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;new_quantity&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;LineItemRemoved&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;line-item-removed&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;item_id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OrderLine&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;item_id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;product&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;unit_price&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Order&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;types&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;lines&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;list&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OrderLine&lt;/span&gt;&lt;span&gt;}]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.{&lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;LineItemRemoved&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;OrderCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;QuantityAdjusted&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;order_id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;customer&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;lines&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;OrderCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;order_id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;event_source_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;customer&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;customer_name&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;children &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;lines&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;identified_by&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;item_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;item_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;item_id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;item_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;product&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;product_name&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;initial_quantity&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;unit_price&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;unit_price&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;QuantityAdjusted&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;item_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;new_quantity&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;removed_with &lt;/span&gt;&lt;span&gt;LineItemRemoved&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;item_id&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-3-4&quot; aria-labelledby=&quot;tab-3-4&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;childrenFrom&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;removedWith&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;setFrom&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/chronicle&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;field&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/fundamentals&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// Events&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;customerName&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;itemId&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;empty&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;productName&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;initialQuantity&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;unitPrice&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;QuantityAdjusted&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;itemId&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;empty&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;newQuantity&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;eventType&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LineItemRemoved&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;itemId&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;empty&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// Read Models&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderLine&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;empty&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;setFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;productName&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;product&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;setFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;initialQuantity&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;setFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QuantityAdjusted&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;newQuantity&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;setFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;unitPrice&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;unitPrice&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Order&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;empty&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;setFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;OrderCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;customerName&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;customer&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;childrenFrom&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;itemId&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;removedWith&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LineItemRemoved&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;itemId&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;field&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Array&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; genericArguments&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;OrderLine&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;lines&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderLine&lt;/span&gt;&lt;span&gt;&lt;span&gt;[]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[];&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;starlight-tabs-restore&gt;&lt;/starlight-tabs-restore&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;It works, and I’d argue it’s readable as long as you already know the attribute vocabulary. But look at &lt;code dir=&quot;auto&quot;&gt;Quantity&lt;/code&gt;. Two different events set it, so the story of that one property is spread over two attributes. The story of the &lt;em&gt;line&lt;/em&gt; is spread over an attribute on the class and attributes on its members, and the story of the removal is up on the parent. To answer “what happens when an item is removed?” you read the whole thing.&lt;/p&gt;
&lt;p&gt;Here is the same read model as a fluent projection, with a plain read model next to it:&lt;/p&gt;
&lt;starlight-tabs data-sync-key=&quot;language&quot;&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-4-0&quot; id=&quot;tab-4-0&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-4-1&quot; id=&quot;tab-4-1&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Kotlin&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-4-2&quot; id=&quot;tab-4-2&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-4-3&quot; id=&quot;tab-4-3&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Elixir&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-4-4&quot; id=&quot;tab-4-4&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-4-0&quot; aria-labelledby=&quot;tab-4-0&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderSummary&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Customer&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IEnumerable&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;OrderSummaryLine&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; Lines&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderSummaryLine&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Product&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Quantity&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;decimal&lt;/span&gt;&lt;span&gt;&lt;span&gt; UnitPrice&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderSummaryProjection&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;OrderSummary&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Define&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;OrderSummary&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; builder&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;From&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;OrderCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Set&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Customer&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;To&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;CustomerName&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Children&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Lines&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; children &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;children&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IdentifiedBy&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;l &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Id&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;From&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;UsingKey&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ItemId&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Set&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;l &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Product&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;To&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ProductName&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Set&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;l &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Quantity&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;To&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;InitialQuantity&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;From&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;QuantityAdjusted&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;UsingKey&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ItemId&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Set&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;l &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Quantity&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;To&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;NewQuantity&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;RemovedWith&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;LineItemRemoved&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;_ &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;UsingKey&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ItemId&lt;/span&gt;&lt;span&gt;)));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-4-1&quot; aria-labelledby=&quot;tab-4-1&quot; role=&quot;tabpanel&quot; tabindex=&quot;0&quot; hidden&gt;&lt;blockquote&gt;
&lt;p&gt;Kotlin does not support this workflow yet.
The fluent children builder has no &lt;code dir=&quot;auto&quot;&gt;removedWith&lt;/code&gt;-equivalent method, so the line removal in this example can only be expressed with the model-bound &lt;code dir=&quot;auto&quot;&gt;@RemovedWith&lt;/code&gt; on a &lt;code dir=&quot;auto&quot;&gt;@ChildrenFrom&lt;/code&gt; property, as in the model-bound example above.&lt;/p&gt;
&lt;/blockquote&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-4-2&quot; aria-labelledby=&quot;tab-4-2&quot; role=&quot;tabpanel&quot; tabindex=&quot;0&quot; hidden&gt;&lt;blockquote&gt;
&lt;p&gt;Java does not support this workflow yet.
The fluent children builder has no &lt;code dir=&quot;auto&quot;&gt;removedWith&lt;/code&gt;-equivalent method, so the line removal in this example can only be expressed with the model-bound &lt;code dir=&quot;auto&quot;&gt;@RemovedWith&lt;/code&gt; on a &lt;code dir=&quot;auto&quot;&gt;@ChildrenFrom&lt;/code&gt; property, as in the model-bound example above.&lt;/p&gt;
&lt;/blockquote&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-4-3&quot; aria-labelledby=&quot;tab-4-3&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OrderSummaryLine&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;item_id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;product&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;unit_price&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OrderSummary&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModel&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;types&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;lines&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;list&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OrderSummaryLine&lt;/span&gt;&lt;span&gt;}]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;order_id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;customer&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;lines&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OrderSummaryProjection&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projections&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Projection&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;model&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;OrderSummary&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.{&lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;LineItemRemoved&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;OrderCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;QuantityAdjusted&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;OrderCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;order_id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;event_source_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;customer&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;customer_name&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;children &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;lines&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;identified_by&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;item_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;item_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;item_id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;item_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;product&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;product_name&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;initial_quantity&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;unit_price&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;unit_price&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from &lt;/span&gt;&lt;span&gt;QuantityAdjusted&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;item_id&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;new_quantity&lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;removed_with &lt;/span&gt;&lt;span&gt;LineItemRemoved&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;item_id&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-4-4&quot; aria-labelledby=&quot;tab-4-4&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;projection&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/chronicle&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderSummaryLine&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;empty&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;product&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;unitPrice&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderSummary&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;empty&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;customer&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;lines&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderSummaryLine&lt;/span&gt;&lt;span&gt;&lt;span&gt;[]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[];&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;projection&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderSummaryProjection&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;implements&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IProjectionFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;OrderSummary&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;define&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IProjectionBuilderFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;OrderSummary&lt;/span&gt;&lt;span&gt;&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;OrderCreated&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;customer&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;customerName&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;children&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;OrderSummaryLine&lt;/span&gt;&lt;span&gt;&gt;(&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;lines&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;children&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;children&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;identifiedBy&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;usingKey&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;itemId&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;product&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;productName&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;initialQuantity&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;QuantityAdjusted&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;usingKey&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;itemId&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;quantity&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;newQuantity&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;removedWith&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;LineItemRemoved&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;usingKey&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;itemId&lt;/span&gt;&lt;span&gt;)));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;starlight-tabs-restore&gt;&lt;/starlight-tabs-restore&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;It isn’t shorter, and I won’t pretend it is. What changed is the shape of the reading. The two records at the top are the read model, and you can take them in at a glance, with no Chronicle attributes on them. The projection reads top to bottom as a description of the &lt;em&gt;order’s life&lt;/em&gt;: created, line added, quantity adjusted, line removed. The question “what happens when an item is removed?” has one line to point at.&lt;/p&gt;
&lt;p&gt;Notice what’s missing, too. &lt;code dir=&quot;auto&quot;&gt;UnitPrice&lt;/code&gt; has no mapping. Auto-mapping is on by default in fluent projections, so a property whose name matches an event property is mapped for you, and only &lt;code dir=&quot;auto&quot;&gt;Product&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;Quantity&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;Customer&lt;/code&gt; need an explicit &lt;code dir=&quot;auto&quot;&gt;Set&lt;/code&gt; because their event properties are named differently. Same rule as in model-bound, just not written down anywhere you have to look at.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;what-you-get-by-pulling-them-apart&quot;&gt;What you get by pulling them apart&lt;/h2&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A read model you can read.&lt;/strong&gt; A plain record that says what a screen or an API will see, and nothing about how it was built. The docs call this out as the point of the fluent style: the read model stays free of Chronicle attributes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Room for the harder parts.&lt;/strong&gt; Joins, nested children, event context and transformations all have a home in the builder, and the docs recommend declarative projections for exactly those shapes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A projection you can share.&lt;/strong&gt; The docs list sharing one projection definition across several read models as a reason to go declarative.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The same tests.&lt;/strong&gt; A &lt;a href=&quot;https://www.cratis.io/chronicle/testing/read-models/scenario/&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;ReadModelScenario&lt;/code&gt;&lt;/a&gt; discovers a model-bound projection, an &lt;code dir=&quot;auto&quot;&gt;IProjectionFor&amp;#x3C;T&gt;&lt;/code&gt; or a reducer for the read model type on its own, so switching styles doesn’t mean rewriting the specification.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;what-it-costs&quot;&gt;What it costs&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;It’s more code, and the docs say so plainly. There’s also a price the attributes don’t charge: two things have to agree. The read model lives in one file, the mapping in another, and renaming a property means you have to remember there’s a second place that cares. The compiler helps, since the builder uses lambdas over your properties and a rename shows up as a build error. But a reader now has to hold two files in their head, which is, funnily enough, the exact thing model-bound saves you from.&lt;/p&gt;
&lt;p&gt;That’s the whole trade. Cohesion on one side, readability and a clean read model on the other. Neither is the grown-up option.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;projection-or-reducer&quot;&gt;Projection or reducer?&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;This is the one I most want to get straight, because “fluent” and “reducer” both sound like “write some code that builds the read model”, and they’re not the same thing at all.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/projection-or-reducer.BdEQiXdb_86kQU.webp&quot; alt=&quot;A diagram titled Declare it or compute it. Two columns. Projection: you declare the mapping, runs in the kernel, set add count clear, and changing it means a partial or full replay. Reducer: you write the fold, runs in your app, any code you write, and changing it means a full replay.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;2100&quot;&gt;&lt;/p&gt;
&lt;p&gt;A fluent projection is still a &lt;strong&gt;declaration&lt;/strong&gt;. You describe what each event does to the read model, and Chronicle runs that description for you in the projection engine, inside the kernel. The operations on offer are a short list: set, add, subtract, increment, decrement, count and clear.&lt;/p&gt;
&lt;p&gt;A &lt;a href=&quot;https://www.cratis.io/chronicle/reducers/&quot;&gt;reducer&lt;/a&gt; is &lt;strong&gt;code&lt;/strong&gt;. It’s an &lt;code dir=&quot;auto&quot;&gt;IReducerFor&amp;#x3C;TModel&gt;&lt;/code&gt; in your application with one method per event. Chronicle sends it the event and the current state, and it returns the next state. The kernel streams events to it and stores whatever it returns. Here is the same book once more, this time as a reducer:&lt;/p&gt;
&lt;starlight-tabs data-sync-key=&quot;language&quot;&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-5-0&quot; id=&quot;tab-5-0&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-5-1&quot; id=&quot;tab-5-1&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Kotlin&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-5-2&quot; id=&quot;tab-5-2&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Java&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-5-3&quot; id=&quot;tab-5-3&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Elixir&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-5-4&quot; id=&quot;tab-5-4&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;TypeScript&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-5-0&quot; aria-labelledby=&quot;tab-5-0&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Reducers&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Title&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;bool&lt;/span&gt;&lt;span&gt;&lt;span&gt; IsBorrowed&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; BorrowedBy&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusReducer&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IReducerFor&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OnBookRegistered&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;span&gt;&lt;span&gt; @event&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; current&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;EventContext&lt;/span&gt;&lt;span&gt;&lt;span&gt; context&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Id&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;context&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Value&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Title&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;@event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Title&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;@event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IsBorrowed&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;BorrowedBy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OnBookBorrowed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt; @event&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; current&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;EventContext&lt;/span&gt;&lt;span&gt;&lt;span&gt; context&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;current&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;with&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IsBorrowed&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;BorrowedBy&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;@event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;MemberName&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OnBookReturned&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;&lt;span&gt; @event&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; current&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;EventContext&lt;/span&gt;&lt;span&gt;&lt;span&gt; context&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;current&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;with&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IsBorrowed&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;BorrowedBy&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-5-1&quot; aria-labelledby=&quot;tab-5-1&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; io.cratis.chronicle.observation.Reducer&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; title: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; isbn: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; isBorrowed: &lt;/span&gt;&lt;span&gt;Boolean&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;val&lt;/span&gt;&lt;span&gt; borrowedBy: &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;? &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@Reducer&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusReducer&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;choosingStyleBookRegistered&lt;/span&gt;&lt;span&gt;(event: &lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;span&gt;): &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;title &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; event.title,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;isbn &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; event.isbn,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;isBorrowed &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;borrowedBy &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;choosingStyleBookBorrowed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;event: &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;current: &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;): &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;current.&lt;/span&gt;&lt;span&gt;copy&lt;/span&gt;&lt;span&gt;(isBorrowed &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;, borrowedBy &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; event.memberName)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;fun&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;choosingStyleBookReturned&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;event: &lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;current: &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;): &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;current.&lt;/span&gt;&lt;span&gt;copy&lt;/span&gt;&lt;span&gt;(isBorrowed &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;, borrowedBy &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-5-2&quot; aria-labelledby=&quot;tab-5-2&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;io&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;observation&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Reducer&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; title&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;boolean&lt;/span&gt;&lt;span&gt;&lt;span&gt; isBorrowed&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;String&lt;/span&gt;&lt;span&gt;&lt;span&gt; borrowedBy&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;Reducer&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusReducer&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;choosingStyleBookRegistered&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;choosingStyleBookBorrowed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;current&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;current&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;current&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;memberName&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;choosingStyleBookReturned&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;current&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;current&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;current&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-5-3&quot; aria-labelledby=&quot;tab-5-3&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;defstruct&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&quot;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;is_borrowed&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;borrowed_by&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nil&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;defmodule&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Reducers&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BookStatusReducer&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Reducers&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Reducer&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;model&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;alias&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;.{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;handles&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;handles&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;handles&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;impl&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;reduce&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; event&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;_model&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;_context&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;MyApp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;is_borrowed&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;borrowed_by&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nil&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;reduce&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt;{}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; event&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; model&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;_context&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;model &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;is_borrowed&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;borrowed_by&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;member_name&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;reduce&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;&lt;span&gt;{},&lt;/span&gt;&lt;span&gt; model&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;_context&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;model &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;is_borrowed&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;borrowed_by&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nil&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-5-4&quot; aria-labelledby=&quot;tab-5-4&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;reducer&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/chronicle&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;isBorrowed&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;borrowedBy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// Handler methods receive the event, the current state, and an optional EventContext&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// as a third argument; this reducer does not need the context.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// The method name must be the exact camelCase of the event&apos;s class name -&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// Chronicle discovers handlers by name, not by parameter type.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;reducer&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;undefined&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusReducer&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;choosingStyleBookRegistered&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;current&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;undefined&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isbn&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;isBorrowed&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;borrowedBy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;choosingStyleBookBorrowed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;current&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;current&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; isBorrowed&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; borrowedBy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;memberName&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;choosingStyleBookReturned&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookReturned&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;current&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;return&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;current&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; isBorrowed&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; borrowedBy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;null&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;starlight-tabs-restore&gt;&lt;/starlight-tabs-restore&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;For the TypeScript reducer, handler methods only receive the event and the current state, with no event context, so that example leaves out &lt;code dir=&quot;auto&quot;&gt;Id&lt;/code&gt;. Everything else is the same idea: a fold over state instead of a definition of a mapping.&lt;/p&gt;
&lt;p&gt;Three differences matter in practice:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Where it runs, and what it can express.&lt;/strong&gt; A projection runs in the kernel and is limited to the operations above. A reducer runs in your app, so branching, derived values, totals with guard logic and temporal state are all just code. &lt;code dir=&quot;auto&quot;&gt;current&lt;/code&gt; has to be nullable, because the first event for an instance arrives before there’s any state, and it’s on you to keep the method free of side effects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What a change costs.&lt;/strong&gt; The kernel can look at a changed projection definition and, in some cases, replay only part of it. A changed reducer implementation needs a full replay. &lt;a href=&quot;https://blog.cratis.io/from-event-to-read-model/#when-attributes-cant-say-it-reducers&quot;&gt;&lt;em&gt;From event to read model&lt;/em&gt;&lt;/a&gt; has the details of how Chronicle classifies those changes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How you test it.&lt;/strong&gt; A reducer is a plain method, so the easiest test is to call it with an event and a state. A projection you’d run through a scenario. Both work with &lt;code dir=&quot;auto&quot;&gt;ReadModelScenario&lt;/code&gt;, as the next section shows.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The practical rule is the one the docs give: use the simplest style that keeps the intent obvious. And a reducer builds state, just like a projection does. If what you want is for something to &lt;em&gt;happen&lt;/em&gt; when an event arrives, an email or a follow-up event, that’s a reactor, and &lt;a href=&quot;https://blog.cratis.io/reacting-to-facts/&quot;&gt;&lt;em&gt;Reacting to facts&lt;/em&gt;&lt;/a&gt; is about those.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;choosing&quot;&gt;Choosing&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.cratis.io/_astro/which-style.j38qm6WH_Z1inSOE.webp&quot; alt=&quot;A flow titled Pick the simplest style that reads clearly. Do attributes say it clearly? Yes leads to Model-bound, least code. No leads to Joins, children, or a plain model? Yes leads to Fluent, IProjectionFor of T. No leads to Easier to read as code? Yes leads to Reducer, state in, state out.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1900&quot;&gt;&lt;/p&gt;
&lt;p&gt;I’d put it in that order and I’d follow it honestly. Model-bound first. If you catch yourself scrolling to work out where a property comes from, or you want the read model free of attributes, move the mapping into a fluent projection. If the thing you’re describing is really a calculation, write the reducer.&lt;/p&gt;
&lt;p&gt;And it isn’t a one-way door. Here is the book as a model-bound read model, a fluent one and a reducer, fed the same history through the same scenario:&lt;/p&gt;

&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Keys&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Testing&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Specifications&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Xunit&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;when_a_book_is_borrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Specification&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt; _bookId &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;New&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReadModelScenario&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookStatusModelBound&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; _modelBound &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReadModelScenario&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookStatusFluent&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; _fluent &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReadModelScenario&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;BookStatusReducerModel&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; _reducer &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Because&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;object&lt;/span&gt;&lt;span&gt;&lt;span&gt;[]&lt;/span&gt;&lt;span&gt; history &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookRegistered&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Dune&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;9780441013593&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookBorrowed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Ada&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_modelBound&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Given&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ForEventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_bookId&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;history&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_fluent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Given&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ForEventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_bookId&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;history&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_reducer&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Given&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ForEventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_bookId&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;history&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;should_flag_the_model_bound_book_as_borrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_modelBound&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IsBorrowed&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldBeTrue&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;should_flag_the_fluent_book_as_borrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_fluent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IsBorrowed&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldBeTrue&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;should_flag_the_reduced_book_as_borrowed&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_reducer&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;IsBorrowed&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldBeTrue&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;should_name_the_member_in_the_model_bound_book&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_modelBound&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BorrowedBy&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldEqual&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Ada&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;should_name_the_member_in_the_fluent_book&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_fluent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BorrowedBy&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldEqual&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Ada&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;should_name_the_member_in_the_reduced_book&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_reducer&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BorrowedBy&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldEqual&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Ada&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The same goes for the order from earlier. Feed the model-bound &lt;code dir=&quot;auto&quot;&gt;Order&lt;/code&gt; and the fluent &lt;code dir=&quot;auto&quot;&gt;OrderSummary&lt;/code&gt; one history, with a quantity adjusted and a line removed, and they have to agree:&lt;/p&gt;

&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Keys&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Chronicle&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Testing&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ReadModels&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Specifications&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Xunit&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;when_a_line_is_adjusted_and_another_is_removed&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Specification&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt; _orderId &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;EventSourceId&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;New&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt; _pen &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;NewGuid&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt; _ink &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Guid&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;NewGuid&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReadModelScenario&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Order&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; _modelBound &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;readonly&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ReadModelScenario&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;OrderSummary&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; _fluent &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;async&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Because&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;object&lt;/span&gt;&lt;span&gt;&lt;span&gt;[]&lt;/span&gt;&lt;span&gt; history &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OrderCreated&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Ada&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_pen&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Pen&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;1.5m&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LineItemAdded&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_ink&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Ink&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;4m&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;QuantityAdjusted&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_pen&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LineItemRemoved&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_ink&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_modelBound&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Given&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ForEventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_orderId&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;history&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_fluent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Given&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ForEventSource&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_orderId&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Events&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;history&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;should_keep_one_line_in_the_model_bound_order&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_modelBound&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Lines&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Count&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ShouldEqual&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;should_keep_one_line_in_the_fluent_order&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_fluent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Lines&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Count&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;ShouldEqual&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;should_adjust_the_quantity_in_the_model_bound_order&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_modelBound&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Lines&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Single&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Quantity&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldEqual&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;should_adjust_the_quantity_in_the_fluent_order&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_fluent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Lines&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Single&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Quantity&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldEqual&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Fact&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;should_map_the_price_by_name_in_the_fluent_order&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;_fluent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Instance&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Lines&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Single&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;UnitPrice&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ShouldEqual&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1.5m&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;That’s what makes the choice cheap. Start with attributes. If it stops reading well, move the mapping out, keep the events and the expected state, and let the specification tell you whether you changed behavior. &lt;a href=&quot;https://blog.cratis.io/testing-with-arc-and-chronicle/&quot;&gt;&lt;em&gt;Testing with Arc and Chronicle&lt;/em&gt;&lt;/a&gt; covers the scenarios in more depth.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Model-bound and fluent aren’t rivals. They’re the same engine with the mapping in two different places, and the right one is whichever leaves the next person able to read the read model, or the mapping, without a detour. I said fluent gets undersold. More precisely, it’s what you reach for when cohesion has stopped paying for itself.&lt;/p&gt;
&lt;p&gt;If you want the full reference, the docs have a page for &lt;a href=&quot;https://www.cratis.io/chronicle/projections/declarative/&quot;&gt;declarative projections&lt;/a&gt; and one for &lt;a href=&quot;https://www.cratis.io/chronicle/projections/model-bound/&quot;&gt;model-bound projections&lt;/a&gt;. The next post, &lt;a href=&quot;https://blog.cratis.io/stop-filtering-on-status/&quot;&gt;&lt;em&gt;Stop filtering on status&lt;/em&gt;&lt;/a&gt;, takes the same two styles into a feature that works in both: projection variants.&lt;/p&gt;</content:encoded><category>chronicle</category><category>event-sourcing</category></item><item><title>AuthProxy: the edge your services shouldn&apos;t have to build</title><link>https://blog.cratis.io/authproxy-the-edge-your-services-should-not-build/</link><guid isPermaLink="true">https://blog.cratis.io/authproxy-the-edge-your-services-should-not-build/</guid><description>Sign-in, tenant, identity and invitations are the same chores in every service. AuthProxy is a container you configure at the ingress, in front of services written in anything, so they can assume the request is already authenticated, tenant-scoped and enriched. Here&apos;s how it works, what it buys you in security, and where Arc and Ante fit.</description><pubDate>Sun, 11 Oct 2026 12:00:00 GMT</pubDate><content:encoded>&lt;div&gt;&lt;h2 id=&quot;tldr&quot;&gt;TL;DR&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cratis.io/authproxy/&quot;&gt;AuthProxy&lt;/a&gt; is a container you configure and put in front of your services, at the ingress. It authenticates the request, resolves the tenant, enriches the identity and forwards it all as headers, so each service can assume it’s looking at an authenticated, tenant-scoped request. It doesn’t care what your services are written in. There’s a nice Aspire integration for those who run Aspire, but at its core it’s a container with configuration. Doing this at the edge is also a security win: one place for sign-in, claims checked before anything is forwarded, spoofed headers removed, and a default that fails closed. The price is a trust boundary, because your services believe the proxy. It works with Arc through Arc’s &lt;code dir=&quot;auto&quot;&gt;/.cratis/me&lt;/code&gt; endpoint, and with &lt;a href=&quot;https://github.com/Cratis/Ante&quot;&gt;Ante&lt;/a&gt;, the invitation and onboarding lobby, when someone is signed in but doesn’t belong anywhere yet.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-same-chores-in-every-service&quot;&gt;The same chores in every service&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Let’s face it, nobody wants to write the sign-in handshake twice. Every application grows the same crop of edge concerns: who is this user, which tenant are they in, where does this request go, and how do you bring in somebody who’s been invited but has no account yet. Without a gateway, every service re-implements them, and the copies drift. An OpenID Connect flow here, a tenant lookup there, an invite-acceptance flow in the third one.&lt;/p&gt;
&lt;p&gt;AuthProxy is the gateway that owns those edges. It’s a reverse proxy built on YARP, and there’s no code to write. You configure it in the &lt;code dir=&quot;auto&quot;&gt;Cratis:AuthProxy&lt;/code&gt; section of &lt;code dir=&quot;auto&quot;&gt;appsettings.json&lt;/code&gt;, or with &lt;code dir=&quot;auto&quot;&gt;Cratis__AuthProxy__&lt;/code&gt; environment variables, and run it as a container in front of your services. It’s standalone: it pairs naturally with Arc, but it will sit in front of any backend and frontend you point it at.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A diagram titled The edge in front of your services. A browser, or any client, sends requests to AuthProxy, which authenticates, resolves the tenant and enriches the identity, and then forwards to your services, backend and frontend. A line underneath reads: Services trust the proxy, so only the proxy may reach them.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1500&quot; src=&quot;https://blog.cratis.io/_astro/the-edge-in-front-of-your-services.BpAHG3vI_ZXChf4.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Everything about who the caller is gets settled at the edge.&lt;/em&gt;&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;a-container-you-configure&quot;&gt;A container you configure&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;I want to get one thing across before anything else. AuthProxy is a container, the &lt;a href=&quot;https://hub.docker.com/r/cratis/authproxy&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;cratis/authproxy&lt;/code&gt;&lt;/a&gt; image, and it doesn’t care what your stack looks like. You configure it, and you put it in front of your services at the ingress level, which is the same place you’d put any other reverse proxy.&lt;/p&gt;
&lt;p&gt;Everything it knows about your system is configuration. A service is a base URL for a backend, a frontend or both, and the proxy sends &lt;code dir=&quot;auto&quot;&gt;/api/**&lt;/code&gt; to the backend and everything else to the frontend. This is the quickstart from the repository, with Microsoft Entra ID sign-in and the tenant taken from the host:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;AuthProxy&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Authentication&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;OidcProviders&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Name&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Microsoft&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Type&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Microsoft&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Authority&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;https://login.microsoftonline.com/&amp;#x3C;tenant-id&gt;/v2.0&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;ClientId&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;&amp;#x3C;client-id&gt;&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;ClientSecret&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;&amp;#x3C;client-secret&gt;&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;TenantResolutions&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Strategy&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Host&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;],&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Services&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Backend&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;BaseUrl&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;http://backend:8080/&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Frontend&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;            &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;BaseUrl&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;http://frontend:3000/&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;That’s all of it. Nothing in there says what the backend is written in, because it doesn’t matter.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A diagram titled One container, in front of anything. On the left, cratis/authproxy, a container you configure with settings or environment variables and no code. On the right three rows: backend, any HTTP API; frontend, any SPA or static site; identity details, optional.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1500&quot; src=&quot;https://blog.cratis.io/_astro/a-container-in-front-of-anything.CSOi3U7J_ZxWCnS.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A configured container at the front. Behind it, whatever you already run.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A backend only has to speak HTTP. If it answers &lt;code dir=&quot;auto&quot;&gt;GET /.cratis/me&lt;/code&gt;, the proxy uses that to enrich the identity and to decide who may enter, and Arc answers it for you. If your service doesn’t, you set &lt;code dir=&quot;auto&quot;&gt;ResolveIdentityDetails&lt;/code&gt; to &lt;code dir=&quot;auto&quot;&gt;false&lt;/code&gt; for that service and the proxy never calls it. A frontend is any single-page app or static site.&lt;/p&gt;
&lt;p&gt;So where does Aspire come in? If you run Aspire, there’s a &lt;code dir=&quot;auto&quot;&gt;Cratis.AuthProxy.Aspire&lt;/code&gt; package that wires the container into your AppHost with a fluent API, so you don’t set the environment variables by hand. That’s a convenience for that world. It’s not a requirement, and it’s not how the product works. The docs also have guides for running it on &lt;a href=&quot;https://www.cratis.io/authproxy/azure/&quot;&gt;Azure&lt;/a&gt; and for &lt;a href=&quot;https://www.cratis.io/authproxy/aspire/&quot;&gt;Aspire&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here’s what it handles, in the order a request meets it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Authentication.&lt;/strong&gt; OpenID Connect and OAuth 2.0, with one provider or several, plus JWT bearer. An unauthenticated request is challenged or sent to a provider-selection page.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authorization.&lt;/strong&gt; You can require a claim, such as a role, a group, or a GitHub organization or team, before anything is forwarded. Authenticating everyone is not the same as letting everyone in.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-tenancy.&lt;/strong&gt; The tenant is resolved per request, from the host, a subdomain, a claim, the route or a fixed value. &lt;a href=&quot;https://blog.cratis.io/tenancy-and-identity-end-to-end/&quot;&gt;Part 10 of the series&lt;/a&gt; follows that tenant hop by hop through Arc and Chronicle, so I won’t repeat it here.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Identity enrichment.&lt;/strong&gt; The proxy calls an endpoint on your service and attaches the answer to the forwarded request.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Invitations and the lobby.&lt;/strong&gt; Invite-based onboarding with signed tokens, and a lobby for users who aren’t assigned to a tenant yet.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;what-putting-it-at-the-edge-buys-you&quot;&gt;What putting it at the edge buys you&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Sign-in and authorization are the part of an application where one copy beats ten. Doing them in a proxy at the ingress gives you things that are hard to get by convention:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A diagram titled What the edge gives you. Six cards: sign-in done once, claims checked first, spoofed headers removed, fails closed on doubt, trusted peers only, and sessions encrypted.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1500&quot; src=&quot;https://blog.cratis.io/_astro/what-the-edge-gives-you.BL6Iii9d_Z2jX8R1.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Six things you get from one well-placed container.&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sign-in is done once.&lt;/strong&gt; One OpenID Connect handshake in one place, with Microsoft Entra ID, Google, GitHub, Apple or any other OIDC provider, instead of a copy in every service that slowly drifts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Claims are checked before anything is forwarded.&lt;/strong&gt; Require a role, a group, or a GitHub organization or team, and a request without it never reaches your code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spoofed headers don’t get through.&lt;/strong&gt; The proxy removes inbound identity and tenant headers before it sets its own, so a caller can’t hand your service an identity of their own.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It fails closed.&lt;/strong&gt; Identity verification is required by default, which means only an explicit yes admits a user. More on that below.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It only believes the peers you name.&lt;/strong&gt; The client address and scheme come from forwarded headers, and the proxy trusts them only from &lt;a href=&quot;https://www.cratis.io/authproxy/configuration/trusted-proxies/&quot;&gt;the proxies you declare&lt;/a&gt;. That’s what the sign-in notifications and the &lt;code dir=&quot;auto&quot;&gt;Secure&lt;/code&gt; flag on cookies depend on.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sessions and tokens are encrypted.&lt;/strong&gt; The authentication cookie, the sign-in cookies and the tokens it issues are all encrypted, with keys from &lt;a href=&quot;https://www.cratis.io/authproxy/configuration/data-protection/&quot;&gt;a key store you choose&lt;/a&gt;. If you run more than one replica, they need a shared key store (the file system, Azure Blob or Redis), or users get signed out at random.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It can stay quiet.&lt;/strong&gt; The sign-in surface is public by default, because people have to reach it to sign in. A deployment that shouldn’t be discoverable can use &lt;a href=&quot;https://www.cratis.io/authproxy/configuration/admission/&quot;&gt;capability-only admission&lt;/a&gt;, where nothing answers anyone without a valid capability, and everyone else gets a plain 404.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of that makes it a firewall, and it doesn’t replace your own authorization. It does move the hardest-to-get-right code to one place, and it means your services start from a request that has already been vetted.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;services-trust-the-proxy&quot;&gt;Services trust the proxy&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;I want to be upfront about the trade-off, because it’s the thing that makes the rest work. The identity and tenant reach your services as ordinary HTTP headers. Nothing in them is signed. A service believes them because of where they came from, not because of what they contain.&lt;/p&gt;
&lt;p&gt;That puts the guarantee in your topology. AuthProxy removes any inbound copies of the identity and tenant headers before it sets its own, so a caller can’t smuggle a principal through the proxy. But a backend that can be reached some other way has no such protection. Arc is built around that. By default it doesn’t trust the forwarded identity headers, and requests stay anonymous, until you opt in. The &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/development/generating-principal/&quot;&gt;docs on generating a principal&lt;/a&gt; put the rule plainly: accept these headers only from a trusted authenticated ingress that strips and replaces them, with no bypass route to the backend.&lt;/p&gt;
&lt;p&gt;The same thinking applies to the proxy’s own surroundings. It almost never sees a browser. It sees an ingress controller, a load balancer or a CDN edge, and everything it knows about the client address and scheme comes from the forwarded headers those write. &lt;a href=&quot;https://www.cratis.io/authproxy/configuration/trusted-proxies/&quot;&gt;You tell it which peers are allowed to speak for someone else&lt;/a&gt;, because nobody else can.&lt;/p&gt;
&lt;p&gt;Here’s the backend side for a service that uses Arc. The proxy doesn’t care how a service is built, this is just the Arc flavor of one behind it:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Identity&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; builder &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WebApplication&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;CreateBuilder&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;args&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;builder&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AddCratisArc&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;options &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;options&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;TrustForwardedIdentityHeaders&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;builder&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Services&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AddMicrosoftIdentityPlatformIdentityAuthentication&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;builder&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Services&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AddAuthorization&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt; app &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Build&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;UseAuthentication&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;UseAuthorization&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;UseCratisArc&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;await&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;RunAsync&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LibraryIdentity&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; DisplayName&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LibraryIdentityProvider&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;IProvideIdentityDetails&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;IdentityDetails&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Provide&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IdentityProviderContext&lt;/span&gt;&lt;span&gt;&lt;span&gt; context&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Task&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;FromResult&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IdentityDetails&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;context&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Name&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;blocked&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LibraryIdentity&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;context&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Name&lt;/span&gt;&lt;span&gt;)));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The first line of the registration is the opt-in. The provider at the bottom is the enrichment, which brings me to how the proxy and Arc talk.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;how-authproxy-talks-to-arc&quot;&gt;How AuthProxy talks to Arc&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Arc has a place for “details about the signed-in user that the token doesn’t carry”: an identity details provider. You implement &lt;code dir=&quot;auto&quot;&gt;IProvideIdentityDetails&lt;/code&gt;, and Arc serves what you return at &lt;code dir=&quot;auto&quot;&gt;/.cratis/me&lt;/code&gt;. AuthProxy calls that endpoint on your service and attaches the result to the request it forwards. You write the provider once, and every service behind the ingress benefits.&lt;/p&gt;
&lt;p&gt;The endpoint is also a gate. &lt;code dir=&quot;auto&quot;&gt;IsUserAuthorized&lt;/code&gt; in the provider’s result decides whether the user may enter the application at all. Here’s what the endpoint above returns for a signed-in user, for one the provider turns away, and for a request with no principal (some headers left out):&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;GET /.cratis/me  (principal: Jane)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;HTTP/1.1 200 OK&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Cache-Control: no-store, private&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&quot;id&quot;:&quot;user-1&quot;,&quot;name&quot;:&quot;Jane&quot;,&quot;isAuthenticated&quot;:true,&quot;isAuthorized&quot;:true,&quot;roles&quot;:[&quot;anonymous&quot;,&quot;authenticated&quot;],&quot;details&quot;:{&quot;displayName&quot;:&quot;Jane&quot;}}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;GET /.cratis/me  (principal: blocked)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;HTTP/1.1 403 Forbidden&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;GET /.cratis/me  (no principal)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;HTTP/1.1 401 Unauthorized&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;img alt=&quot;A diagram titled What the proxy asks your service. AuthProxy asks /.cratis/me for each signed-in user. A 200 response with isAuthorized true is forwarded. A 403 from your provider is denied. No answer, or anything unclear, is denied.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1600&quot; src=&quot;https://blog.cratis.io/_astro/what-the-proxy-asks-arc.BLVEUDLh_RTWUS.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Only an explicit yes gets through.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That last sentence is a deliberate change. AuthProxy’s identity verification for a service now defaults to &lt;code dir=&quot;auto&quot;&gt;Required&lt;/code&gt;, where it used to be best effort. Under the old behavior, only a 403 refused a caller, so an unreachable service, a timeout or an unreadable answer let the request through, which meant the gateway was at its most permissive exactly when it knew the least. Now only an explicit &lt;code dir=&quot;auto&quot;&gt;&quot;isAuthorized&quot;: true&lt;/code&gt; admits. The &lt;a href=&quot;https://www.cratis.io/authproxy/upgrading/identity-verification-required-by-default/&quot;&gt;upgrade note&lt;/a&gt; has the full table, and it names the opt-out for a service that needs the old behavior. A service whose identity endpoint is down stops being served, and that’s the intent.&lt;/p&gt;
&lt;p&gt;One caution that’s easy to miss. The identity is presentation data. It tells the frontend who’s here, and it can keep a user out of the application, but it doesn’t authorize your commands and queries. Those are protected by Arc’s own authorization, on the server, whatever the frontend shows. The &lt;a href=&quot;https://www.cratis.io/arc/understanding-identity-and-access/&quot;&gt;identity docs&lt;/a&gt; are blunt about it, and I agree with them.&lt;/p&gt;
&lt;p&gt;Arc is available for the JVM and TypeScript as well, with the same &lt;code dir=&quot;auto&quot;&gt;/.cratis/me&lt;/code&gt; idea. The details of each are in the docs and in Part 10.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;invitations-and-where-ante-fits&quot;&gt;Invitations, and where Ante fits&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Authentication tells you who someone is. It doesn’t tell you they belong. A user who has signed in but has no tenant needs somewhere to go, and that’s what the lobby is for. AuthProxy handles three onboarding outcomes: &lt;a href=&quot;https://www.cratis.io/authproxy/configuration/lobby/invitation-to-organization/&quot;&gt;inviting a user into an existing organization&lt;/a&gt;, &lt;a href=&quot;https://www.cratis.io/authproxy/configuration/lobby/invitation-for-creating-organization/&quot;&gt;inviting a user to create a new one&lt;/a&gt;, and &lt;a href=&quot;https://www.cratis.io/authproxy/configuration/lobby/registration/&quot;&gt;letting a user register on their own&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The invitation flow uses a bootstrap path, &lt;code dir=&quot;auto&quot;&gt;/invite/&amp;#x3C;token&gt;&lt;/code&gt;. The proxy validates the signed token, stages the invitation with the lobby before the user authenticates, sends them to sign in, and then checks again after they come back, so a browser can carry the values but can’t author them. By default, if the invitation’s tenant matches the tenant resolved for the request, the user continues straight into the application. If it doesn’t, they’re sent to the lobby, when one is configured.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A diagram titled An invitation, from link to app. Four steps joined by arrows. Step 1, host invites: Ante signs the link. Step 2, user opens it at AuthProxy. Step 3, proxy checks: stage, sign in, exchange. Step 4, continue to the app or the lobby. A line underneath reads: The host still owns delivery and provisioning.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1500&quot; src=&quot;https://blog.cratis.io/_astro/an-invitation-from-link-to-app.D2kpTA1K_Z11affs.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;From an invitation to a user in the right place.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The other end of that is &lt;a href=&quot;https://github.com/Cratis/Ante&quot;&gt;Ante&lt;/a&gt;. It’s Cratis’ invitation and onboarding lobby. It signs the tokens for invitations your application issues, records when an invitee accepts or registers on their own, and publishes those facts for your application to act on. It’s built on Chronicle, so those facts are events. What it deliberately doesn’t do is own the rest: your application decides who to invite, delivers the link, runs the authenticating proxy and provisions the tenant or the membership. Ante saying “accepted” means it published the fact, not that your system has finished setting anyone up.&lt;/p&gt;
&lt;p&gt;I should be honest about where Ante is. Its own documentation says there is no verified standalone walkthrough yet, with a host, Chronicle, MongoDB and a validating proxy wired together, and it asks you to read &lt;a href=&quot;https://github.com/Cratis/Ante/blob/main/Documentation/security.md&quot;&gt;its security notes&lt;/a&gt; before you deploy. So treat the flow above as a description of how the pieces are meant to fit, and the Ante docs as the source for what it supports today.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;where-it-stops&quot;&gt;Where it stops&lt;/h2&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;AuthProxy isn’t an identity provider. It signs users in with the providers you configure. It’s also not a firewall or a replacement for network controls.&lt;/li&gt;
&lt;li&gt;It doesn’t replace authorization in your services. It decides who gets in and with what identity, and your commands and queries still decide what they may do.&lt;/li&gt;
&lt;li&gt;The guarantee is a network one. If a service can be reached without going through the proxy, its trust in the headers is misplaced.&lt;/li&gt;
&lt;li&gt;It’s configuration, not code, which is the point, but it also means the details live in the &lt;a href=&quot;https://www.cratis.io/authproxy/configuration/&quot;&gt;configuration reference&lt;/a&gt;, and it’s worth reading before you run it for real.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;try-it&quot;&gt;Try it&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The Arc half is easy to try on its own. Create a web project, add the &lt;code dir=&quot;auto&quot;&gt;Cratis.Arc&lt;/code&gt; package, and use the registration above. Then send a request to &lt;code dir=&quot;auto&quot;&gt;/.cratis/me&lt;/code&gt; with the three headers the proxy would send: &lt;code dir=&quot;auto&quot;&gt;x-ms-client-principal&lt;/code&gt; with a base64-encoded client principal, plus &lt;code dir=&quot;auto&quot;&gt;x-ms-client-principal-id&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;x-ms-client-principal-name&lt;/code&gt;. The docs show how to &lt;a href=&quot;https://www.cratis.io/arc/backend/csharp/development/generating-principal/&quot;&gt;build a principal for local development&lt;/a&gt;. Only do that on a loopback host, never on something reachable from the internet.&lt;/p&gt;
&lt;p&gt;For the proxy itself, run the &lt;code dir=&quot;auto&quot;&gt;cratis/authproxy&lt;/code&gt; container with the quickstart configuration above, pointing &lt;code dir=&quot;auto&quot;&gt;Backend&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;Frontend&lt;/code&gt; at your own services, and start from the &lt;a href=&quot;https://www.cratis.io/authproxy/&quot;&gt;AuthProxy docs&lt;/a&gt;. There are guides for &lt;a href=&quot;https://www.cratis.io/authproxy/aspire/&quot;&gt;hosting it with Aspire&lt;/a&gt; and for &lt;a href=&quot;https://www.cratis.io/authproxy/azure/&quot;&gt;running it on Azure&lt;/a&gt; with Microsoft Entra ID sign-in.&lt;/p&gt;
</content:encoded><category>authproxy</category><category>arc</category><category>identity</category><category>tenancy</category></item><item><title>Cratis Components: why it exists, and what agnostic really means</title><link>https://blog.cratis.io/cratis-components-why-it-exists-and-what-agnostic-means/</link><guid isPermaLink="true">https://blog.cratis.io/cratis-components-why-it-exists-and-what-agnostic-means/</guid><description>Arc generates the commands and queries. Cratis Components is the layer that turns them into dialogs, forms and tables, without tying you to a UI library. Here&apos;s why it exists, how it works, and what &apos;agnostic&apos; honestly covers.</description><pubDate>Sun, 11 Oct 2026 11:00:00 GMT</pubDate><content:encoded>&lt;div&gt;&lt;h2 id=&quot;tldr&quot;&gt;TL;DR&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cratis.io/components/&quot;&gt;Cratis Components&lt;/a&gt; is the React layer between Arc’s generated proxies and your screens. It owns the plumbing around commands and queries, so you don’t rebuild it for every dialog and table. It’s independent of any UI library in three ways: its interaction internals are private, its look is yours through tokens and stable parts, and optional adapters can swap a small set of primitives for MUI or PrimeReact. It isn’t a promise that every component can be swapped for another library’s, and it’s React in a browser, nothing else.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;what-sits-between-the-proxy-and-the-pixel&quot;&gt;What sits between the proxy and the pixel&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Arc gives you generated TypeScript for your commands and queries, and that’s a great start. But a proxy is not a screen. Between the proxy and what the user sees there’s a lot of work that looks the same in every application: running a command and tracking its state, showing validation where it belongs, a dialog that closes only when the command worked, a table that subscribes to a query and knows what to show when it’s pending or empty.&lt;/p&gt;
&lt;p&gt;That’s what Components is for. The docs &lt;a href=&quot;https://www.cratis.io/components/why-components/&quot;&gt;put it&lt;/a&gt; as removing what you’d otherwise build in every application: command execution state, validation display, dialogs, observable subscriptions, paging, selection and empty states.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A diagram titled Between the proxies and the pixels. Three cards joined by arrows: Arc, generated proxies, commands and queries; Components, dialogs, forms and tables, the plumbing; and you, your screens, your look. A line underneath reads: Components never fetches or stores your data.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1500&quot; src=&quot;https://blog.cratis.io/_astro/between-the-proxies-and-the-pixels.D2KEaSHN_CWIVV.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Arc generates the contracts, you own the screens, and Components is the plumbing in between.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One thing I like about that boundary is what Components doesn’t do. It never fetches, caches or persists your data. Command execution and query results are Arc’s state. And it has no direct dependency on Chronicle, so it behaves the same over an Arc backend that has no event sourcing at all. If you want the walk through a real screen, &lt;a href=&quot;https://blog.cratis.io/cratis-components-the-react-layer/&quot;&gt;Part 9 of the series&lt;/a&gt; builds the author list and the register dialog with it, and &lt;a href=&quot;https://blog.cratis.io/command-forms-link-the-command-focus-on-the-fields/&quot;&gt;command forms&lt;/a&gt; explains the form part.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;how-it-works&quot;&gt;How it works&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;You import three stylesheets once, mount one provider inside Arc’s, and then import every component from its own subpath. The package root is setup only. In the &lt;code dir=&quot;auto&quot;&gt;cratis&lt;/code&gt; template the stylesheets sit in the CSS entry file:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/components/tokens&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/components/styles&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;@&lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/components/theme&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;And the provider goes inside Arc’s:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;reflect-metadata&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/arc.react&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CratisComponentsProvider&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/components&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;YourApp&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;./YourApp&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;App&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;CratisComponentsProvider&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt;{{&lt;/span&gt;&lt;span&gt; locale&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;en-US&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;toaster&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;YourApp&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;CratisComponentsProvider&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;Arc&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Components renders its own HTML. Simple controls are semantic native elements, and a few interaction details, such as focus, overlays and dates, come from React Aria inside the package. There’s no UI library you have to install to get a working screen.&lt;/p&gt;
&lt;p&gt;That is a change worth being honest about. Components 3 was built on PrimeReact, and installing it brought the PrimeReact dependency tree, its release cadence and its license terms, whether your own code imported PrimeReact or not. Components 4 removes that: its manifest declares no PrimeReact dependency, and a release gate checks that the emitted code has no PrimeReact imports. The reason in the &lt;a href=&quot;https://www.cratis.io/components/ui-foundation/&quot;&gt;docs&lt;/a&gt; is ownership. One token source instead of a translation chain through a third party’s preset, a dependency and license boundary you control, and a public API that evolves on Components’ own cadence.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;what-agnostic-actually-covers&quot;&gt;What “agnostic” actually covers&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;“Agnostic” is one of those words that promises more than it should, so let me say precisely what it means here. There are three layers, and they’re different.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A diagram titled Three kinds of independence. Three rows. One: inside, React Aria stays private. Two: look, –cratis tokens and stable parts. Three: primitives, nine slots from MUI or PrimeReact.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1500&quot; src=&quot;https://blog.cratis.io/_astro/three-ways-to-be-agnostic.BszFAqEd_1T82Yv.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Independent on the inside, in how it looks, and in a few primitives.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Inside.&lt;/strong&gt; React Aria does the focus, keyboard and overlay work, and none of its types, class names or DOM are part of what you depend on. If Components swaps it out later, you don’t migrate. That’s all “renderer-independent” means in the docs, and it’s deliberately not more. The &lt;a href=&quot;https://www.cratis.io/components/decisions/0001-dom-coupled-contract/&quot;&gt;accepted decision&lt;/a&gt; says the public contract is coupled to React and the browser DOM on purpose, so you get real HTML attributes, refs and form behavior. A framework-neutral target, React Native or a terminal UI isn’t what this is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Look.&lt;/strong&gt; Appearance is separated from behavior in three stylesheets: &lt;code dir=&quot;auto&quot;&gt;tokens&lt;/code&gt; defines the &lt;code dir=&quot;auto&quot;&gt;--cratis-*&lt;/code&gt; variables, &lt;code dir=&quot;auto&quot;&gt;styles&lt;/code&gt; is the structure, and &lt;code dir=&quot;auto&quot;&gt;theme&lt;/code&gt; is an optional baseline with dark mode. A product with its own design system skips the theme and maps its own values onto the tokens:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;root&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;--cratis-primary-color&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;--product-accent&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;--cratis-surface-card&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;--product-surface&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;--cratis-text-color&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;--product-text&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;--cratis-focus-ring&lt;/span&gt;&lt;span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;var&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;--product-focus-ring&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;For one component, documented parts carry a &lt;code dir=&quot;auto&quot;&gt;data-cratis-part&lt;/code&gt; attribute and take ordinary HTML attributes through a &lt;code dir=&quot;auto&quot;&gt;pt&lt;/code&gt; prop. The &lt;a href=&quot;https://www.cratis.io/components/styling/&quot;&gt;styling guide&lt;/a&gt; covers the cascade, and Part 9 covers the Tailwind trap.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Primitives.&lt;/strong&gt; This is where MUI and PrimeReact come in. An optional adapter swaps in that library’s version of a small set of primitives. You pick it on the provider:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CratisComponentsProvider&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/components&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;muiUiLibrary&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/components.mui&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Application&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;CratisComponentsProvider&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt;{{&lt;/span&gt;&lt;span&gt; locale&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;en-US&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;library&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;muiUiLibrary&lt;/span&gt;&lt;span&gt;}&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;Application content&lt;/span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;CratisComponentsProvider&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;There are &lt;a href=&quot;https://www.cratis.io/components/renderers/&quot;&gt;adapters for MUI, for PrimeReact 11 and for PrimeReact 10&lt;/a&gt;. If you’ve heard that Components supports PrimeReact and MUI out of the box, this is the current shape: the built-in renderer is the default, and the adapters are optional packages that you install and version together with Components.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;what-an-adapter-cant-swap&quot;&gt;What an adapter can’t swap&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;This is the part I’d most like you to remember. An adapter covers exactly nine slots: button, icon button, text input, text area, checkbox, radio, switch, progress bar and surface. Dialogs, dropdowns, date pickers, tooltips and the table paginator stay with Components, and so do the composites. A &lt;code dir=&quot;auto&quot;&gt;DataPage&lt;/code&gt; under the MUI adapter is still a &lt;code dir=&quot;auto&quot;&gt;DataPage&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A diagram titled What an adapter can swap. On the left: the adapter can change nine primitives, such as button, input, checkbox and switch. On the right: stays with Components, everything else, including dialogs, dropdowns, date pickers, tables, CommandDialog and DataPage.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1500&quot; src=&quot;https://blog.cratis.io/_astro/what-an-adapter-swaps.CtOxSeRg_Z2uIQyz.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Nine primitives can come from another library. The rest is Components.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You can see that boundary in the markup. The same &lt;code dir=&quot;auto&quot;&gt;&amp;#x3C;Button&gt;Save&amp;#x3C;/Button&gt;&lt;/code&gt; renders as an element with the class &lt;code dir=&quot;auto&quot;&gt;cratis-button&lt;/code&gt; by default, and with MUI’s &lt;code dir=&quot;auto&quot;&gt;MuiButton-root&lt;/code&gt; classes under the adapter. Both keep the same &lt;code dir=&quot;auto&quot;&gt;data-cratis-part=&quot;root&quot;&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;data-variant=&quot;solid&quot;&lt;/code&gt; attributes. A command form behaves the same way: an empty title still gets the message from your C# rule under the right field with either renderer.&lt;/p&gt;
&lt;p&gt;That’s what I’d call agnostic without the hand-waving. The behavior is Components’, the primitives can be someone else’s, and the contract in between is stable. If a screen needs something a vendor grid does, the &lt;a href=&quot;https://www.cratis.io/components/renderers/unsupported/&quot;&gt;adapter docs&lt;/a&gt; point to using that grid next to Components, and not inside it.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;when-not-to-use-it&quot;&gt;When not to use it&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Use Components for screens that consume generated commands and queries. For a one-off element with no Cratis behavior, native HTML or your own component is the better answer, and the two mix without a fuss. The tables sort and filter the page that’s loaded, so a filter over a whole result is still a query argument that the server applies. And if you’re not on React in a browser, this isn’t the library.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;where-to-go-next&quot;&gt;Where to go next&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Start with the &lt;a href=&quot;https://www.cratis.io/components/tutorial/&quot;&gt;Components tutorial&lt;/a&gt;, which builds a live list-and-detail screen, and read Part 9 for what the template does with it. If you’re coming from Components 3, the &lt;a href=&quot;https://www.cratis.io/components/migration/3-to-4/&quot;&gt;migration guide&lt;/a&gt; has the steps. And if you pick an adapter, install it at exactly the same version as &lt;code dir=&quot;auto&quot;&gt;@cratis/components&lt;/code&gt;, because each adapter release requires its own matching version.&lt;/p&gt;
</content:encoded><category>components</category><category>react</category><category>arc</category></item><item><title>Command forms: link the command, focus on the fields</title><link>https://blog.cratis.io/command-forms-link-the-command-focus-on-the-fields/</link><guid isPermaLink="true">https://blog.cratis.io/command-forms-link-the-command-focus-on-the-fields/</guid><description>Most of a form isn&apos;t the fields. A command form links a form to a command by its type, so you write the fields and Arc handles the state, the validation and the errors. And because it&apos;s all typed, the compiler guards the way for you, and for your AI assistant.</description><pubDate>Sun, 11 Oct 2026 10:00:00 GMT</pubDate><content:encoded>&lt;div&gt;&lt;h2 id=&quot;tldr&quot;&gt;TL;DR&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;A command form links a form to a command by its &lt;strong&gt;type&lt;/strong&gt;. &lt;a href=&quot;https://www.cratis.io/arc/frontend/react/command-form/&quot;&gt;Arc’s &lt;code dir=&quot;auto&quot;&gt;CommandForm&lt;/code&gt;&lt;/a&gt; owns one instance of the generated command, and you write the fields that bind to its properties. Validation, errors under the right field and execution state come with it. &lt;a href=&quot;https://www.cratis.io/components/commandform/&quot;&gt;Cratis Components&lt;/a&gt; builds fields, dialogs and steppers on top. Everything is typed from the C# command to the field, which means the compiler tells you when you got it wrong. It checks that a property exists, though, not that the control you picked fits it.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;most-of-a-form-isnt-the-fields&quot;&gt;Most of a form isn’t the fields&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Let’s face it, the fields are the easy part. A text box for a title, a number box for pages. It’s everything around them that eats your day: state for every input, validation rules that have to match the backend, getting a rejection from the server back to the field it was about, disabling the button while it’s busy, and doing all of that again for the next form.&lt;/p&gt;
&lt;p&gt;I’ve always wanted that part to go away. The idea behind a command form is to give you an abstraction where you point at a command by its type and then only care about the input fields. Everything else follows from the command.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;link-the-command-not-the-state&quot;&gt;Link the command, not the state&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Take a command that adds a book to a library. This is the backend, in a project made from the &lt;code dir=&quot;auto&quot;&gt;cratis&lt;/code&gt; template:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;namespace&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Library&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Books&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;AddBook&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;Command&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AddBook&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Title&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Author&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Pages&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;BookId&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;BookAdded&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Handle&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;BookId&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;New&lt;/span&gt;&lt;span&gt;&lt;span&gt;(),&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Title&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Author&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Pages&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;EventType&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;record&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BookAdded&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Title&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;&lt;span&gt; Author&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;&lt;span&gt; Pages&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AddBookValidator&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CommandValidator&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;AddBook&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AddBookValidator&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;RuleFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;c &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Title&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;NotEmpty&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;RuleFor&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;c &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;Pages&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;GreaterThan&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A command with three properties and two rules. Nothing about a form in sight. When the project builds, Arc’s proxy generator writes &lt;code dir=&quot;auto&quot;&gt;AddBook.ts&lt;/code&gt; next to it, with the properties and a TypeScript version of the same rules:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;class&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AddBookValidator&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;extends&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CommandValidator&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;IAddBook&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;constructor&lt;/span&gt;&lt;span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;super&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ruleFor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;pages&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;greaterThan&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ruleFor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span&gt;notEmpty&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Rules defined once in C# end up in the browser. The &lt;a href=&quot;https://blog.cratis.io/validation-all-the-way-down/&quot;&gt;validation post&lt;/a&gt; goes into where a rule can live and which rejections reach a field. Now the form. This is a dialog, built with &lt;a href=&quot;https://www.cratis.io/components/commanddialog/&quot;&gt;Cratis Components&lt;/a&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;CommandDialog&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/components/CommandDialog&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;InputTextField&lt;/span&gt;&lt;span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;NumberField&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/components/CommandForm&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;AddBook&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;./AddBook&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AddBookDialog&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;CommandDialog&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;AddBook&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;Add book&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;okLabel&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;Add&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;cancelLabel&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;Cancel&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;InputTextField&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;AddBook&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;Title&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;InputTextField&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;AddBook&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;author&lt;/span&gt;&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;Author&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;NumberField&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;AddBook&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;pages&lt;/span&gt;&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;Pages&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;span&gt;CommandDialog&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;That’s the whole thing. No state, no &lt;code dir=&quot;auto&quot;&gt;onChange&lt;/code&gt;, no error handling, no submit handler. &lt;code dir=&quot;auto&quot;&gt;CommandDialog&lt;/code&gt; creates the command instance, the fields bind to its properties through the accessor, and the dialog runs the command when you confirm. The &lt;a href=&quot;https://www.cratis.io/components/commandform/&quot;&gt;CommandForm docs&lt;/a&gt; describe what a field binds to, and &lt;a href=&quot;https://www.cratis.io/arc/frontend/react/command-form/&quot;&gt;Arc’s own &lt;code dir=&quot;auto&quot;&gt;CommandForm&lt;/code&gt;&lt;/a&gt; is what’s underneath if you want the form without a dialog.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A diagram titled You write the fields. On the left a card reads: you write, the fields, one typed accessor each. On the right four rows list what comes with it: the command instance, validation from your C# rules, errors under the right field, and execution and busy state.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1600&quot; src=&quot;https://blog.cratis.io/_astro/who-writes-what-in-a-form.tq3jad8F_2bArw9.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The fields are yours. The rest comes with the command.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Here’s what that buys you. Leave the Title field empty and move on, and the message from your C# rule appears under that field, with the input marked invalid. The Author field next to it is left alone. Type a title and the message goes away. A property that’s still unset keeps the form invalid, and a &lt;code dir=&quot;auto&quot;&gt;CommandDialog&lt;/code&gt; keeps its confirm button disabled until it’s valid. When the server rejects something instead, the rejection finds its way back to the field it names, and &lt;a href=&quot;https://blog.cratis.io/cratis-components-the-react-layer/&quot;&gt;Part 9 of the series&lt;/a&gt; follows a taken name all the way back to the &lt;code dir=&quot;auto&quot;&gt;Name&lt;/code&gt; field.&lt;/p&gt;
&lt;p&gt;One more thing I like. Arc isn’t only for .NET. It also runs on Spring Boot on the JVM, and both generate against the same TypeScript packages. The form above would be the same code whichever backend sits behind it.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-type-is-the-guard-rail&quot;&gt;The type is the guard rail&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The accessor &lt;code dir=&quot;auto&quot;&gt;c =&gt; c.title&lt;/code&gt; isn’t a string. It’s a function over the generated &lt;code dir=&quot;auto&quot;&gt;AddBook&lt;/code&gt; type, so the compiler knows what &lt;code dir=&quot;auto&quot;&gt;c&lt;/code&gt; is. Misspell the property and you’re told:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;error TS2551: Property &apos;titel&apos; does not exist on type &apos;AddBook&apos;. Did you mean &apos;title&apos;?&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Forget the type parameter on the field, and &lt;code dir=&quot;auto&quot;&gt;c&lt;/code&gt; is no longer an &lt;code dir=&quot;auto&quot;&gt;AddBook&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;error TS18046: &apos;c&apos; is of type &apos;unknown&apos;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;That’s why every field in the docs is written &lt;code dir=&quot;auto&quot;&gt;InputTextField&amp;#x3C;AddBook&gt;&lt;/code&gt;. The part I care about most is the one that crosses the language boundary. Rename &lt;code dir=&quot;auto&quot;&gt;Title&lt;/code&gt; to &lt;code dir=&quot;auto&quot;&gt;Name&lt;/code&gt; in C# and build, and the proxy is regenerated without &lt;code dir=&quot;auto&quot;&gt;title&lt;/code&gt;. The next TypeScript build fails at exactly the field that used it:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;error TS2339: Property &apos;title&apos; does not exist on type &apos;AddBook&apos;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;img alt=&quot;A diagram titled From C# to the field. Three cards joined by arrows: the C# command AddBook with Title, Author and Pages; the generated AddBook.ts with properties and rules; and your field, c =&gt; c.title, a typed accessor. An arrow from the field leads to a red card: build fails, the property is gone. A line underneath reads: Rename it in C#, and the build finds the field.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1500&quot; src=&quot;https://blog.cratis.io/_astro/from-csharp-to-the-field.Bce4xhNx_1N1lbn.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A rename in C# is a compile error at the field, not a surprise in the browser.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In the age of agentic programming, I think this matters more than it used to. An AI assistant happily writes a plausible property name, and a plausible name is not the same as a name that exists. A compile error with a “did you mean” is a guard rail that doesn’t depend on anyone reading carefully. Good for humans, good for AI.&lt;/p&gt;
&lt;p&gt;I want to be straight about how far that guard rail goes, though. It checks that the property exists. It doesn’t check that the control fits it. A &lt;code dir=&quot;auto&quot;&gt;NumberField&lt;/code&gt; bound to the string property &lt;code dir=&quot;auto&quot;&gt;title&lt;/code&gt; compiles without complaint, because the accessor only has to return &lt;em&gt;something&lt;/em&gt;. Choosing the right control for a type is still on you, or on &lt;code dir=&quot;auto&quot;&gt;AutoCommandForm&lt;/code&gt;, which picks the control from the property’s type for you.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;pick-the-shape-you-need&quot;&gt;Pick the shape you need&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;A form in a dialog is only one way to use it, and Components has a few others on top of Arc’s &lt;code dir=&quot;auto&quot;&gt;CommandForm&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;A diagram titled What sits on top of a command form. Three cards on top: CommandDialog, in a dialog, confirm and cancel; CommandStepper, in steps, one command; AutoCommandForm, generated fields from the type. Below them a row reads: fields, InputTextField, NumberField and more. At the bottom a row reads: Arc’s CommandForm, one command, validation, state.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;3200&quot; height=&quot;1500&quot; src=&quot;https://blog.cratis.io/_astro/what-sits-on-top.CKUJZ75i_P1nOE.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Dialogs, steppers and generated forms all sit on the same command form.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;CommandStepper&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;StepperCommandDialog&lt;/code&gt; split one command over several named steps, for &lt;a href=&quot;https://www.cratis.io/components/multi-step-form/&quot;&gt;a multi-step form&lt;/a&gt;. And when you don’t want to write a field per property at all, &lt;code dir=&quot;auto&quot;&gt;AutoCommandForm&lt;/code&gt; generates them from the command’s own properties:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;AutoCommandForm&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;@cratis/components/CommandForm&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;AddBook&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;./AddBook&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;export&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;AddBookForm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;AutoCommandForm&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;command&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;AddBook&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;footer&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&amp;#x3C;&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;submit&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;Add&lt;/span&gt;&lt;span&gt;&amp;#x3C;/&lt;/span&gt;&lt;/span&gt;&lt;span&gt;button&lt;/span&gt;&lt;span&gt;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;/&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A string gets an &lt;code dir=&quot;auto&quot;&gt;InputTextField&lt;/code&gt;, a number a &lt;code dir=&quot;auto&quot;&gt;NumberField&lt;/code&gt;, a boolean a &lt;code dir=&quot;auto&quot;&gt;CheckboxField&lt;/code&gt; and a date a &lt;code dir=&quot;auto&quot;&gt;CalendarField&lt;/code&gt;. Fields are the same components you’d write by hand, and &lt;a href=&quot;https://www.cratis.io/components/commandform/auto-command-form/&quot;&gt;you can register your own&lt;/a&gt; for other types.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;where-it-stops&quot;&gt;Where it stops&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Some honest limits, because a form abstraction that pretends to be everything ends up in the way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The accessor has to be a simple property access like &lt;code dir=&quot;auto&quot;&gt;c =&gt; c.title&lt;/code&gt;. Binding resolves a property name, not an arbitrary expression.&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;AutoCommandForm&lt;/code&gt; leaves out properties it has no field for, such as nested objects, arrays and enums. If one of those is not optional, you need to seed it, or the form stays invalid. Generated titles come from the property names, and there’s no way to override one except writing that field yourself.&lt;/li&gt;
&lt;li&gt;Don’t put an &lt;code dir=&quot;auto&quot;&gt;AutoCommandForm&lt;/code&gt; inside a &lt;code dir=&quot;auto&quot;&gt;CommandDialog&lt;/code&gt;. Each creates its own command instance, so what the user types would never reach the command the dialog runs. Write the fields by hand in dialogs and steppers.&lt;/li&gt;
&lt;li&gt;Components is a React layer for Arc’s generated contracts. It’s a good fit for screens that run commands and show queries, and it isn’t trying to be a design system for everything else.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;try-it&quot;&gt;Try it&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;You can see all of this with the official template. Create a project, add the command above as &lt;code dir=&quot;auto&quot;&gt;Books/AddBook/AddBook.cs&lt;/code&gt; and the dialog as &lt;code dir=&quot;auto&quot;&gt;Books/AddBook/AddBookDialog.tsx&lt;/code&gt;, then build to generate the proxy:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;dotnet&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;install&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Cratis.Templates&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;dotnet&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;cratis&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-n&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Library&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Library&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;dotnet&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;install&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Then rename a property in the C# command and build again. Watching the frontend build point at the field you forgot is the quickest way I know of to see what “typed all the way” means. If you want to go further, the &lt;a href=&quot;https://www.cratis.io/components/tutorial/&quot;&gt;Components tutorial&lt;/a&gt; builds a live list-and-detail screen, and Part 9 covers how the rest of the dialog’s behavior is built.&lt;/p&gt;
</content:encoded><category>arc</category><category>components</category><category>react</category><category>validation</category></item></channel></rss>