<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
    <channel>
      <title>蔓生庭院</title>
      <link>https://garden.linusboyle.cn</link>
      <description>最近的20条笔记 on 蔓生庭院</description>
      <generator>Quartz -- quartz.jzhao.xyz</generator>
      <item>
    <title>memory consistency model</title>
    <link>https://garden.linusboyle.cn/idea/memory-consistency-model</link>
    <guid>https://garden.linusboyle.cn/idea/memory-consistency-model</guid>
    <description><![CDATA[ &lt;h2 id=&quot;memory-consistency-model&quot;&gt;memory consistency model&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#memory-consistency-model&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;memory models&lt;/strong&gt;: the semantics of shared memory. WMM deals with ordering constraints, but is not just reordering.&lt;/p&gt;
&lt;p&gt;Every hardware architecture has its own memory model. &lt;a href=&quot;../idea/memory-barrier-(fence)&quot; class=&quot;internal alias&quot; data-slug=&quot;idea/memory-barrier-(fence)&quot;&gt;memory barrier (fence)&lt;/a&gt;  can be used to enforce ordering constraints.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;../idea/Sequential-Consistency&quot; class=&quot;internal alias&quot; data-slug=&quot;idea/Sequential-Consistency&quot;&gt;Sequential Consistency&lt;/a&gt;  is the simpliest memory model.&lt;/p&gt;
&lt;h3 id=&quot;operational-semantics&quot;&gt;Operational semantics&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#operational-semantics&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The operational semantics can be given in small steps semantics. The system is composed of a &lt;em&gt;thread subsystem&lt;/em&gt; and a &lt;em&gt;storage subsystem&lt;/em&gt; (effectively &lt;a href=&quot;../idea/变迁系统&quot; class=&quot;internal alias&quot; data-slug=&quot;idea/变迁系统&quot;&gt;LTS&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The thread subsystem interpret the sequential program in each thread. It might take internal steps, which does not use memory (such as operation on registers, so ), or take a step that requires memory access &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.0435em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.13889em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.05764em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8491em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mrel mtight&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.01968em;&quot;&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9463em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.13889em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7519em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.05764em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7519em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. (The access or fences are represented as labels &lt;code&gt;l&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;The memory model defines how the storage subsystem works. It describes the effect of memory access and fences. It might take internal steps as well.&lt;/p&gt;
&lt;p&gt;The whole system either takes internal step of either subsystem, or take steps with matching labels.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../idea/SC-operational-semantics&quot; class=&quot;internal alias&quot; data-slug=&quot;idea/SC-operational-semantics&quot;&gt;SC operational semantics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../idea/TSO-operational-semantics&quot; class=&quot;internal alias&quot; data-slug=&quot;idea/TSO-operational-semantics&quot;&gt;TSO operational semantics&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;/p&gt;&lt;blockquote class=&quot;transclude&quot; data-url=&quot;Classification-of-memory-consistency-model&quot; data-block=&quot;&quot; data-embed-alias=&quot;undefined&quot;&gt;&lt;a href=&quot;../idea/Classification-of-memory-consistency-model&quot; class=&quot;transclude-inner internal alias&quot; data-slug=&quot;idea/Classification-of-memory-consistency-model&quot;&gt;Transclude of Classification-of-memory-consistency-model&lt;/a&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt; ]]></description>
    <pubDate>Thu, 07 May 2026 13:50:47 GMT</pubDate>
  </item><item>
    <title>concurrent termination analysis</title>
    <link>https://garden.linusboyle.cn/idea/concurrent-termination-analysis</link>
    <guid>https://garden.linusboyle.cn/idea/concurrent-termination-analysis</guid>
    <description><![CDATA[ &lt;h2 id=&quot;背景&quot;&gt;背景&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#背景&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;In concurrent event-driven programming, consider device drivers  that provide event-handling services of independent threads, while communicating through  shared memory. These device drivers are permitted by operating system to temporarily take  over the execution of the threads in which the event occurred. A scenario could occur, where a  loop in the code executed by the device driver could diverge when a relevant shared variable is  modified by other threads in the same driver. Such scenarios could potentially cause denial of   service, rendering the entire system unavailable. Hence, we see that non-terminating execution scenarios can greatly compromise the underlying computing environment’s reliability.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;THREAD_STUCK_IN_DEVICE_DRIVER (stop code 0x100000ea)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../idea/images/Pasted-image-20220301192128.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;相关工作&quot;&gt;相关工作&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#相关工作&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;testing&quot;&gt;Testing&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#testing&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Testing Non-termination in Multi-threaded programs, 2016 Priyanka Thyagarajan’s master’s thesis&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When we proceed to examine testing, we observe: Testing based methods are adept at verifying properties that can be expressed as assertions. Testing is a technique that requires a program to terminate. Traditionally, nontermination is a property that cannot be expressed as assertions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;verification&quot;&gt;Verification&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#verification&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;rely-guarantee/static analysis:
&lt;ul&gt;
&lt;li&gt;Compositional termination proofs for multi-threaded programs&lt;/li&gt;
&lt;li&gt;Rely-Guarantee Termination and Cost Analyses of Loops with Concurrent Interleavings&lt;/li&gt;
&lt;li&gt;Proving Thread Termination&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;abstraction
&lt;ul&gt;
&lt;li&gt;Proving Liveness of Parameterized Programs&lt;/li&gt;
&lt;li&gt;Transition predicate abstraction and fair termination&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Model checking based (old)
&lt;ul&gt;
&lt;li&gt;some new paper:&lt;/li&gt;
&lt;li&gt;Fair Termination for Parameterized Probabilistic Concurrent Systems&lt;/li&gt;
&lt;li&gt;Liveness of Randomised Parameterised Systems under Arbitrary Schedulers (这部份主要是关注概率并发程序)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;GPU
&lt;ul&gt;
&lt;li&gt;Termination analysis for GPU kernels (&lt;em&gt;Proving termination by thread-modular analysis&lt;/em&gt;, 也和rely/guarantee有关)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Unlike CPU applications, which may be reactive, GPU kernels are &lt;em&gt;required&lt;/em&gt; to terminate: any data computed by a kernel is inaccessible from the CPU as long as the kernel has not terminated. Besides the data being inaccessible, kernels with accidental infinite loops can have a severe impact on the systems on which they run: while working on the experiments from &lt;a href=&quot;https://www.sciencedirect.com/science/article/pii/S0167642317300849#br0110&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;11&lt;/a&gt;, we accidentally introduced infinite loops on numerous occasions; this often made our systems unresponsive, and sometimes caused transient hardware failures and spontaneous reboots.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;研究内容&quot;&gt;研究内容&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#研究内容&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;研究高效的并发程序终止性证明方法，能从实际安全攸关代码如驱动程序中寻找到可能的非终止问题。应用符号化方法应对并发程序的状态空间过大的问题。&lt;/p&gt;
&lt;h2 id=&quot;技术方案&quot;&gt;技术方案&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#技术方案&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;rely-guarantee条件的学习/重用&lt;/li&gt;
&lt;li&gt;&lt;del&gt;termination under &lt;a href=&quot;../idea/memory-consistency-model&quot; class=&quot;internal alias&quot; data-slug=&quot;idea/memory-consistency-model&quot;&gt;WMM&lt;/a&gt;&lt;/del&gt; compilation under WMM which preserves termination&lt;/li&gt;
&lt;/ol&gt; ]]></description>
    <pubDate>Thu, 07 May 2026 13:50:47 GMT</pubDate>
  </item><item>
    <title>Non-Volatile Memory</title>
    <link>https://garden.linusboyle.cn/idea/Non-Volatile-Memory</link>
    <guid>https://garden.linusboyle.cn/idea/Non-Volatile-Memory</guid>
    <description><![CDATA[ &lt;h1 id=&quot;non-volatile-memory-nvm&quot;&gt;Non-Volatile Memory (NVM)&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#non-volatile-memory-nvm&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Specifically referred to Persistent Memory devices like &lt;a href=&quot;../idea/Intel-Optane-DIMMs&quot; class=&quot;internal alias&quot; data-slug=&quot;idea/Intel-Optane-DIMMs&quot;&gt;Intel Optane DIMMs&lt;/a&gt;, not traditional storages.&lt;/p&gt;
&lt;h2 id=&quot;what-is-persistent-memory&quot;&gt;What is Persistent Memory&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#what-is-persistent-memory&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Persistent Memory (PMEM), also referred to as Non-Volatile Memory (NVM), or Storage Class Memory (SCM), provides a new entry in the memory-storage hierarchy shown in Figure 2 that fills the performance/capacity gap.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;../Pasted-image-20230109144446.png&quot; width=&quot;auto&quot; height=&quot;auto&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/p&gt;
&lt;p&gt;持久内存可以像DRAM一样随机访问，同时拥有和传统硬件媲美的空间。一般可以通过和传统存储设备同样的IO接口进行访问，也可以把持久内存当成DRAM来使用，如此在传统架构上编写的程序可以正常在持久内存上运行；要发挥全部特性，则需要考虑PM的持久性，即需要用户确保持久内存上数据的一致性。由于系统产生各种意外中断的可能性，这就要求限制数据写回持久内存的顺序。&lt;/p&gt;
&lt;h2 id=&quot;what-does-pm-mean-for-application-developers&quot;&gt;What does PM mean for application developers?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#what-does-pm-mean-for-application-developers&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The introduction of a persistent memory tier &lt;strong&gt;offers application developers a choice of where to put data and data structures&lt;/strong&gt;. Traditionally data was read and written to volatile memory and flushed to non-volatile persistent storage. When the application is started, data has to be read from storage into volatile memory before it can be accessed. Depending on the size of the working dataset, this can take seconds, minutes, or hours. With clever application design, developers and application architects can now take advantage of this new technology to improve performance and reduce application startup times.&lt;/p&gt;
&lt;p&gt;Persistent Memory introduces &lt;strong&gt;some new programming concerns, which did not apply to traditional, volatile memory&lt;/strong&gt;. These include:&lt;/p&gt;
&lt;p&gt;Data Persistence:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Stores are not guaranteed to be persistent until flushed&lt;/strong&gt;. Although this is also true for the decades-old memory-mapped file APIs (like mmap() and msync() on Linux), many programmers have not dealt with the need to flush to persistence for memory. Following the standard API (like msync() to flush changes to persistence) will work as expected. But more optimal flushing, where the application flushes stores from the CPU caches directly, instead of calling into the kernel, is also possible.&lt;/li&gt;
&lt;li&gt;CPUs have out-of-order CPU execution and cache access/flushing. This means if two values are stored by the application, &lt;strong&gt;the order in which they become persistent may not be the order that the application wrote them&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Data Consistency:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;8-byte stores are powerfail atomic on the x86 architecture — if a powerfail happens during an aligned, 8-byte store to PMEM, either the old 8-bytes or the new 8-bytes (not a combination of the two) will be found in that location after reboot.&lt;/li&gt;
&lt;li&gt;Anything larger than 8-bytes on x86 is not powerfail atomic, so it is up to software to implement whatever transactions/logging/recovery is required for consistency. Note that this is specific to x86 — other hardware platforms may have different atomicity sizes (PMDK is designed so applications using it don’t have to worry about these details).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Memory Leaks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Memory leaks to persistent storage are persistent. Rebooting the server doesn’t change the on-device contents. In the current volatile model, if an application leaks memory, restarting the application or system frees that memory.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Byte Level Access:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Application developers can read and write at the byte level according to the application requirements. The read/writes no longer need to be aligned or equal to storage block boundaries, eg: 512byte, 4KiB, or 8KiB. The storage doesn’t need to read an entire block to modify a few bytes, to then write that entire block back to persistent storage. Applications are free to read/write as much or as little as required. This improves performance and reduces memory footprint overheads.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Error Handling:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Applications may need to detect and handle hardware errors directly. Since applications have direct access to the persistent memory media, any errors will be returned back to the application as memory errors.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;characteristics&quot;&gt;Characteristics&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#characteristics&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Persistent&lt;/li&gt;
&lt;li&gt;Byte-addressable&lt;/li&gt;
&lt;li&gt;Low latency&lt;/li&gt;
&lt;li&gt;High capacity&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;challenge&quot;&gt;Challenge&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#challenge&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Programmers must ensure the &lt;a href=&quot;../idea/Crash-Consistency&quot; class=&quot;internal alias&quot; data-slug=&quot;idea/Crash-Consistency&quot;&gt;Crash Consistency&lt;/a&gt; of their programs (a.k.a crash safety). This is because NVM hardwares usually have weak persistency semantics (due to presence of cache). Certain operations (e.g. flush and fence) can be used to constrain the &lt;em&gt;persist order&lt;/em&gt;, but require a lot of knowledge and is expensive.&lt;/p&gt;
&lt;p&gt;Note providing &lt;a href=&quot;../idea/Strict-Persistency&quot; class=&quot;internal alias&quot; data-slug=&quot;idea/Strict-Persistency&quot;&gt;Strict Persistency&lt;/a&gt; solves the problem (‘Cause any post-crash state is a valid volatile state), like Intel eADR, but this is hard in reality.&lt;/p&gt;
&lt;p&gt;Semantics models of NVM weak persistency behavious include&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Px86, with formalized semantics of Intel-x86 persistency (two variants): &lt;a href=&quot;../idea/Persistency-semantics-of-the-Intel-x86-architecture&quot; class=&quot;internal alias&quot; data-slug=&quot;idea/Persistency-semantics-of-the-Intel-x86-architecture&quot;&gt;Persistency semantics of the Intel-x86 architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;DPTSO, a varaint of Px86 with synchronous flushes: &lt;a href=&quot;../idea/Taming-x86-TSO-persistency&quot; class=&quot;internal alias&quot; data-slug=&quot;idea/Taming-x86-TSO-persistency&quot;&gt;Taming x86-TSO persistency&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;visibility-and-persistency&quot;&gt;Visibility and Persistency&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#visibility-and-persistency&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Visibility and persistence are often not the same thing, and changes made to persistent memory are often visible to other running threads in the system before they are persistent.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Data Visibility由架构的Memory Model决定。类似的，Persistency的顺序由Persistency Model决定。&lt;/p&gt;
&lt;p&gt;Persistency Model for Intel-X86:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. Raad, J. Wickerson, G. Neiger, and V. Vafeiadis, ‘Persistency semantics of the Intel-x86 architecture’, Proc. ACM Program. Lang., vol. 4, no. POPL, p. 11:1-11:31, Jan. 2020, doi: 10.1145/3371079. &lt;a href=&quot;../idea/Persistency-semantics-of-the-Intel-x86-architecture&quot; class=&quot;internal alias&quot; data-slug=&quot;idea/Persistency-semantics-of-the-Intel-x86-architecture&quot;&gt;Persistency semantics of the Intel-x86 architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A. Khyzha and O. Lahav, ‘Taming x86-TSO persistency’, Proc. ACM Program. Lang., vol. 5, no. POPL, pp. 1–29, Jan. 2021, doi: 10.1145/3434328. &lt;a href=&quot;../idea/Taming-x86-TSO-persistency&quot; class=&quot;internal alias&quot; data-slug=&quot;idea/Taming-x86-TSO-persistency&quot;&gt;Taming x86-TSO persistency&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Persistency Model for ARMv8:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. Raad, J. Wickerson, and V. Vafeiadis, ‘Weak persistency semantics from the ground up: formalising the persistency semantics of ARMv8 and transactional models’, Proc. ACM Program. Lang., vol. 3, no. OOPSLA, p. 135:1-135:27, Oct. 2019, doi: 10.1145/3360561.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;relevant-works&quot;&gt;Relevant Works&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#relevant-works&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;2023&quot;&gt;2023&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#2023&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Memento: A Framework for Detectable Recoverability in Persistent Memory (PLDI)&lt;/li&gt;
&lt;li&gt;Mumak: Efficient and Black-Box Bug Detection for Persistent Memory (EuroSys)&lt;/li&gt;
&lt;li&gt;Spirea: A Mechanized Concurrent Separation Logic for Weak Persistent Memory (OOPSLA, distinguised)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;2024&quot;&gt;2024&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#2024&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../idea/Discovering-Likely-Program-Invariants-for-Persistent-Memory&quot; class=&quot;internal alias&quot; data-slug=&quot;idea/Discovering-Likely-Program-Invariants-for-Persistent-Memory&quot;&gt;Discovering Likely Program Invariants for Persistent Memory&lt;/a&gt; (ASE)&lt;/li&gt;
&lt;/ul&gt; ]]></description>
    <pubDate>Thu, 07 May 2026 13:50:47 GMT</pubDate>
  </item><item>
    <title>Dependent Function</title>
    <link>https://garden.linusboyle.cn/idea/20260507025950-Dependent-Function</link>
    <guid>https://garden.linusboyle.cn/idea/20260507025950-Dependent-Function</guid>
    <description><![CDATA[ &lt;p&gt;A function where the type of its return value is dependent on the value of its argument. That is, the co-domain is not fixed.&lt;/p&gt;
&lt;h2 id=&quot;dependent-function-type-pi-type&quot;&gt;Dependent Function Type (&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;Π&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;-Type)&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#dependent-function-type-pi-type&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The type of a dependent function can be described with this notation:&lt;/p&gt;
&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;Π&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mrel mtight&quot;&gt;∈&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1774em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.05017em;&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;If B is a constant function, then this type is reduced to ordinary function type &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.05017em;&quot;&gt;B&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;related&quot;&gt;Related&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#related&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Dependent Type Theory&lt;/li&gt;
&lt;/ul&gt; ]]></description>
    <pubDate>Thu, 07 May 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>Evaluating Combat Tricks In Limited</title>
    <link>https://garden.linusboyle.cn/source/clipped/Evaluating-Combat-Tricks-In-Limited</link>
    <guid>https://garden.linusboyle.cn/source/clipped/Evaluating-Combat-Tricks-In-Limited</guid>
    <description><![CDATA[ &lt;p&gt;&lt;a href=&quot;https://ajax.starcitygames.com/products/7493&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://static.starcitygames.com/sales/cardscans/MTG/UDS/en/nonfoil/Opposition.jpg&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;What he said was that, because the format has a lot of creatures with high toughness relative to their power, blocking is good, and combat tricks are worse. I argued that the opposite is true, that because creatures have higher toughness, combat tricks are better than they would otherwise be.&lt;/p&gt;
&lt;p&gt;I stand by my position here, but his point isn’t exactly wrong; it was just missing a step. Regardless, I think unpacking both positions, as well as discussing evaluations and uses of combat tricks in Limited, is a worthwhile topic. This is especially true for players who mostly know Constructed, as combat tricks are rare there (and mostly used for &lt;a href=&quot;http://www.starcitygames.com/tags/TomRoss&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;combo kills&lt;/a&gt;), so it can be easy to not build a lot of experience evaluating the nuances of building with, playing with, and evaluating tricks from a Constructed perspective.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ajax.starcitygames.com/products/1216531&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://static.starcitygames.com/sales/cardscans/MTG/SOI/en/nonfoil/ExposeEvil.jpg&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt; &lt;a href=&quot;https://ajax.starcitygames.com/products/1216411&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://static.starcitygames.com/sales/cardscans/MTG/SOI/en/nonfoil/JacesScrutiny.jpg&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;At the most basic level, a combat trick is something of a split card that can function as a removal spell or a protection spell (or direct damage spell, I suppose). You’ll usually get a good rate (they don’t tend to cost much mana), but the situations where you can use it to do what you want are somewhat more rare or require some work to engineer.&lt;/p&gt;
&lt;p&gt;Combat tricks are generally better in aggressive decks than controlling decks because aggressive decks tend to have cheaper creatures, which are smaller, which attack into larger creatures. When the opponent blocks, the trick allows you to kill the larger creature for much less mana than the larger creature cost (ideally while also pushing damage because other creatures were able to get through unblocked, as having the trick allowed you to attack with all of your creatures).&lt;/p&gt;
&lt;p&gt;The larger you creatures are, the less they need tricks to win in combat. Also, it’s much better to play a trick on your turn than on your opponent’s turn. In order to use a trick on your opponent’s turn, you must leave mana unspent to have the option, and then if they don’t play into it, you may not get the opportunity to profitably spend the mana. Also, if you use a trick on your opponent’s turn, it’s very likely that their mana will be untapped, which means they’ll be able to cast any tricks or removal spells of their own, which makes trying to use your trick much more of a gamble.&lt;/p&gt;
&lt;p&gt;This is the heart of Ben’s argument. If blocking is good, combat tricks are bad. That sentence isn’t accurate; if blocking is good, combat tricks are good, because the scenario where you want to use them will come up more. What Ben really meant was, “If blocking is good enough that you want to plan to block rather than attack, combat tricks are bad.”&lt;/p&gt;
&lt;p&gt;Combat tricks will generally perform best in aggressive decks, and if all the aggressive decks are bad, combat tricks will also be bad. However, if blocking is good, combat tricks will be the best way to draft an aggressive deck that can beat a deck that is trying to block, which was the heart of my argument.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ajax.starcitygames.com/products/1216439&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://static.starcitygames.com/sales/cardscans/MTG/SOI/en/nonfoil/RiseFromTheTides.jpg&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I would unpack this evaluation a little differently. The more good removal there is, the worse combat tricks are, and the more decks there are that don’t rely on combat, the worse combat tricks are. In &lt;em&gt;Shadows over Innistrad&lt;/em&gt;, the fact that your opponent might be playing a U/R &lt;a href=&quot;https://starcitygames.com/search/?card_name=Rise%20from%20the%20Tides&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Rise from the Tides&lt;/a&gt; deck makes combat tricks less likely, as there will be some matches where you’ll have trouble finding a profitable spot to use one. This, analogously, is why combat tricks aren’t played in Constructed. Too many decks don’t rely on creature combat or perhaps don’t play creatures at all. Removal, especially efficient, instant-speed removal, is far more common.&lt;/p&gt;
&lt;p&gt;If control decks are good, they usually won’t want tricks, which means aggressive decks can get them easily. If control decks are so good that aggressive decks are bad, tricks will usually be pretty bad, but most tricks are actually best when aggressive decks and control decks that play larger creatures and try to block are both good. If only aggressive decks are good, tricks aren’t generally that great, because you’re never getting the highest payoff, killing a large blocker.&lt;/p&gt;
&lt;p&gt;Details matter, and not all tricks are created the same.&lt;/p&gt;
&lt;p&gt;First, not all tricks just increase power and toughness, and different keywords are clearly differently suited to different strategies.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ajax.starcitygames.com/products/382710&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://static.starcitygames.com/sales/cardscans/MTG/DKA/en/nonfoil/DeadlyAllure.jpg&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Deathtouch is at its best in a deck that’s trying to block with small creatures. Large creatures don’t need deathtouch, and giving it to an attacker isn’t great because you’ll usually lose your creature, which isn’t productive, and a trick that gives deathtouch isn’t going to give much power, so it won’t be effective as a “burn” spell to end the game. Tricks that give deathtouch are basically “tempo” cards for control decks; they let you play two spells a turn and kill an attacker. They also work well on defense because they’re good “counter-tricks.” If your opponent plays a trick and you answer with this, you negate their edge at worst and maybe also save your creature, depending on the card.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ajax.starcitygames.com/products/38299&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://static.starcitygames.com/sales/cardscans/MTG/RAV/en/nonfoil/GazeOfTheGorgon.jpg&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://starcitygames.com/search/?card_name=Regeneration&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Regeneration&lt;/a&gt;, protection, and indestructibility are best in decks with large creatures, unlike most tricks. This is fairly simple: the larger investment you make in a single creature, the most valuable it is to protect it. This is even more important in decks with Auras, as the investment is even larger.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ajax.starcitygames.com/products/513317&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://static.starcitygames.com/sales/cardscans/MTG/THS/en/nonfoil/TritonTactics.jpg&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Tricks that untap a creature are interesting to place. Such spells are best cast on your opponent’s turn to create a surprise blocker. This means the trick will be used defensively, but you’re only getting to do that if your creature is already tapped, which means you probably needed to be attacking. These tricks are best in aggressive decks against other aggressive decks, especially if your aggressive deck has evasive creatures, as you had to be able to attack without telegraphing the trick and then have them attack into it after leaving it up for the maximum benefit.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ajax.starcitygames.com/products/725274&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://static.starcitygames.com/sales/cardscans/MTG/DDN/en/nonfoil/SwiftJustice.jpg&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;First strike is best on offense because it’s generally extremely vulnerable to a counter-trick, which means you really want to play it when the opponent is tapped out. Also, if you’re aggressive, it’s more likely you have creatures with high power and low toughness, where first strike is best.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ajax.starcitygames.com/products/392630&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://static.starcitygames.com/sales/cardscans/MTG/AVR/en/nonfoil/LeapOfFaith.jpg&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Flying is tricky; while granting reach (as in the mechanic) is obviously best in a control deck, granting the &lt;em&gt;other&lt;/em&gt; kind of reach (as in the ability to kill an opponent who has established control of the battlefield) is best in an aggressive deck. In both cases, evaluating this is going to depend on the needs of your deck, and obviously, in both cases, it will be best when your creatures don’t already have flying, not only because it’s redundant on a creature that already has it but because you’ll have less need for it in a single instant.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ajax.starcitygames.com/products/57516&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://static.starcitygames.com/sales/cardscans/MTG/M10/en/nonfoil/MightOfOaks.jpg&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Sizing of pump spells also matters and needs to be evaluated in the context of a set specifically. As a simplified example, if most of the good common two-drops are 2/1 and the good three drops are 3/2, an instant that gives a creature +1/+1 will be very weak; its only effect among those creatures will to be save the three-mana creature from the two mana creature. If, on the other hand, good two-drops are 2/2 and good three-drops are 2/3, a trick that gives +1/+1 will be relatively strong, allowing any creature to kill another other creature and live.&lt;/p&gt;
&lt;p&gt;This principle is why, in general, power/toughness tricks are better in formats that have more toughness than power and worse in formats that have more power than toughness; clearly, the reverse is true of tricks that grant first strike or protection.&lt;/p&gt;
&lt;p&gt;Also, the more similar creatures are in size, the better pump spells that only give small bonuses are. In a set with Eldrazi, where one player is likely to have 2/2s and the other 8/8s, &lt;a href=&quot;https://starcitygames.com/search/?card_name=Giant%20Growth&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Giant Growth&lt;/a&gt; is a horrible card. In a set where the biggest creatures you can find are around 4/4, like the original &lt;em&gt;Mirrodin&lt;/em&gt;, &lt;a href=&quot;https://starcitygames.com/search/?card_name=Giant%20Growth&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Giant Growth&lt;/a&gt; is at its best (and, in fact, I think Predator’s Strike is the best green common in that set, while it wouldn’t be in most sets).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ajax.starcitygames.com/products/1061677&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://static.starcitygames.com/sales/cardscans/MTG/DD3/en/nonfoil/EVG/GiantGrowth.jpg&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt; &lt;a href=&quot;https://ajax.starcitygames.com/products/26036&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://static.starcitygames.com/sales/cardscans/MTG/MRD/en/nonfoil/PredatorsStrike.jpg&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It’s good to develop a sense of how good pump spells generally are in a format, but honestly, it’s not that important how good they are in general. Because they’re very rarely extremely early picks, you’ll almost always be evaluating them in the context of a deck whose needs and creatures you know something about.&lt;/p&gt;
&lt;p&gt;Where I think most players are giving up the most value is in sideboarding with combat tricks. Sideboarding is generally not a topic that gets enough attention, and Limited doesn’t get much attention these days. When people do talk about sideboarding, it’s usually a sideboarding guide for Constructed, and when they talk about Limited, it’s usually card evaluation. Combat tricks are among the most common and important cards to sideboard in or out.&lt;/p&gt;
&lt;p&gt;First, consider siding out any combat trick your opponent has seen. This doesn’t mean you should always cut them, because how they’re positioned in the matchup is definitely more important than “have they seen it?”, but you’ll get some value from their knowledge of it without having it in your deck, as they’ll play around it, and it’ll be harder to use well for the same reason.&lt;/p&gt;
&lt;p&gt;More importantly, after playing a game, you’ll have a lot more information about creature sizing. Rather than trying to know the set well enough to find generalities about how big creatures are relative to each other, you can write down the size of all the creatures your opponent plays, look at the size of all the creatures in your deck, and then look at how often a particular combat trick will make one of your smaller creatures beat one of their larger creatures. You might realize that your aggressive white deck full of 2/2s doesn’t want a +2/+2 trick against a green deck with mana creatures and 6/5s but that the same trick great against a U/B defensive deck with a lot of 3/3s and 2/4s.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ajax.starcitygames.com/products/45916&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://static.starcitygames.com/sales/cardscans/MTG/10E/en/nonfoil/GrizzlyBears.jpg&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Obviously, don’t just consider combat tricks in your maindeck; also consider how any in your sideboard would impact likely combat steps, and don’t just consider combat. If your opponent has a lot of removal spells that care about the size of your creatures, think about how effective your tricks would be at saving them and how likely the game is to play out in a way where you can have mana to cast them at the right time. If your opponent has &lt;a href=&quot;https://starcitygames.com/search/?card_name=Lightning%20Strike&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Lightning Strike&lt;/a&gt;, &lt;a href=&quot;https://starcitygames.com/search/?card_name=Giant%20Growth&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Giant Growth&lt;/a&gt; might not actually be good at saving your &lt;a href=&quot;https://starcitygames.com/search/?card_name=Hill%20Giant&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Hill Giant&lt;/a&gt; because they’ll just kill it on turn 4, but if they have &lt;a href=&quot;https://starcitygames.com/search/?card_name=Burn%20Trail&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Burn Trail&lt;/a&gt;, it will be good at protecting your &lt;a href=&quot;https://starcitygames.com/search/?card_name=Grizzly%20Bears&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Grizzly Bears&lt;/a&gt; because you’ll have untapped before they have enough mana to cast it. (Why you care about protecting your &lt;a href=&quot;https://starcitygames.com/search/?card_name=Grizzly%20Bears&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Grizzly Bears&lt;/a&gt; is a separate, and relevant, question.)&lt;/p&gt;
&lt;p&gt;Also, there are certain spots where tricks can change value relative to their expectations in other ways. For example, if you have a large creature and you know your opponent’s only way to deal with it is to block it with multiple creatures, a trick that saves it will be outstanding, even though tricks are generally not good with large creatures (as blocking with several creatures isn’t generally the most common way to deal with them).&lt;/p&gt;
&lt;p&gt;Clearly, this is about fundamentals, ideas that can be applied to any Limited format. I hope this has improved your ability to ask the right questions and consider the right issues when evaluating inclusion of combat tricks in Limited. As Wizards of the Coast has been finding ways to spread them throughout all the colors at common, and various ways to push their power level, this skill is becoming even more important.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.starcitygames.com/events/040616_atlanta_fact_sheet.html&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://static.starcitygames.com/www/images/article/23May2016Banner.jpg&quot; alt=&quot;SCG Tour &lt;sup&gt;®&lt;/sup&gt;Atlanta Open Weekend June 4-5!” border=”1″ /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;!-- .entry-content --&gt;
&lt;div class=&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt; ]]></description>
    <pubDate>Tue, 05 May 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>Who&#039;s The Beatdown?</title>
    <link>https://garden.linusboyle.cn/source/clipped/Who's-The-Beatdown</link>
    <guid>https://garden.linusboyle.cn/source/clipped/Who's-The-Beatdown</guid>
    <description><![CDATA[ &lt;p&gt;&lt;img src=&quot;http://static.starcitygames.com/www/images/article/dojologo.gif&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Editor’s Note: A long time ago, the first Magic website was The Dojo – a site that is still legendary for publishing some of the most fundamental principles of Magic. Almost all strategical theory can be traced back to the Dojo’s loyal writers, and any serious Magic player owes these old vets a debt of gratitude.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Unfortunately, thanks to financial troubles, The Dojo went out of business in 2000. In a last-ditch effort to save the four years of wisdom that had been collected there at the time, the editor asked the community to archive the articles for future reference. The best of the Dojo articles are reprinted here because they’re still vital to Magic today… merely reprints them, adding links to clarify older cards that new players probably won’t have seen so that they can understand some of the strategy. Many of the Dojo’s writers are still active in Magic and write for other sites; give them a shout-out for helping the community grow.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;**&lt;/p&gt;
&lt;p&gt;Who’s The Beatdown?&lt;/p&gt;
&lt;p&gt;**&lt;/p&gt;
&lt;p&gt;The most common (yet subtle, yet disastrous) mistake I see in tournament Magic is the misassignment of who is the beatdown deck and who is the control deck in a similar deck vs. similar deck matchup. The player who misassigns himself is inevitably the loser.&lt;/p&gt;
&lt;p&gt;You see, in similar deck vs. similar deck matchups, unless the decks are really symmetrical (i.e. the true Mirror match), one deck has to play the role of beatdown, and the other deck has to play the role of control. This can be a very serious dilemma, if, say, both are playing aggressive decks.&lt;/p&gt;
&lt;p&gt;Let me give you an example: At a 1.x PTQ in Washington D. C., my teammate Al Tran was playing for a top 8 slot vs. Sligh. Al was playing Lan D. Ho’s White weenie/Jank deck, normally an aggressive deck… But not vs. Sligh.&lt;/p&gt;
&lt;p&gt;The match was split 1-1, and the third game was going to determine who made top 8.&lt;/p&gt;
&lt;p&gt;Al’s opponent went first and laid a &lt;a href=&quot;https://starcitygames.com/search/?card_name=Jackal%20Pup&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Jackal Pup&lt;/a&gt;. At this point, Al had two &lt;a href=&quot;https://starcitygames.com/search/?card_name=Cursed%20Scroll&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Cursed Scrolls&lt;/a&gt;, two &lt;a href=&quot;https://starcitygames.com/search/?card_name=Swords%20to%20Plowshares&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Swords to Plowshares&lt;/a&gt;, an &lt;a href=&quot;https://starcitygames.com/search/?card_name=Honorable%20Passage&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Honorable Passage&lt;/a&gt;, and some land in hand. Al chose not to Plow the &lt;a href=&quot;https://starcitygames.com/search/?card_name=Jackal%20Pup&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Jackal Pup&lt;/a&gt;, taking 2 on the first attack.&lt;/p&gt;
&lt;p&gt;His opponent played another Pup. Al didn’t Plow either, waiting on Scroll mana or a &lt;a href=&quot;https://starcitygames.com/search/?card_name=Lightning%20Bolt&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Lightning Bolt&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On his own second turn, Al played another land and a &lt;a href=&quot;https://starcitygames.com/search/?card_name=Cursed%20Scroll&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Cursed Scroll&lt;/a&gt;, so he only had one land up.&lt;/p&gt;
&lt;p&gt;On his opponent’s third turn, you guessed it, another &lt;a href=&quot;https://starcitygames.com/search/?card_name=Mountain&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Mountain&lt;/a&gt; came down, followed by &lt;a href=&quot;https://starcitygames.com/search/?card_name=Ball%20Lightning&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Ball Lightning&lt;/a&gt;. Al was forced to Plow the Ball. He gained control over the next few turns, but ended up dying to Bolts.&lt;/p&gt;
&lt;p&gt;What was the problem here? Al was a beatdown deck, and he wanted to deal damage to his opponent via the &lt;a href=&quot;https://starcitygames.com/search/?card_name=Jackal%20Pup&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Jackal Pups&lt;/a&gt;. However, in this particular matchup, he had to play the control deck. You see, Sligh is just much faster than Jank, so Jank’s way to win has to be stifling Sligh’s early speed with removal, and then locking down the midgame with &lt;a href=&quot;https://starcitygames.com/search/?card_name=Cursed%20Scroll&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Cursed Scrolls&lt;/a&gt;. Because Sligh also has &lt;a href=&quot;https://starcitygames.com/search/?card_name=Cursed%20Scroll&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Cursed Scrolls&lt;/a&gt;, as well as more Bolts than Jank, the only way that Jank can win is to make sure it has a decent life total as it plays its own threat cards.&lt;/p&gt;
&lt;p&gt;Though it ostensibly hurts the initial race to give the Sligh player four additional life from the &lt;a href=&quot;https://starcitygames.com/search/?card_name=Jackal%20Pup&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Jackal Pups&lt;/a&gt;, you can see from this example that Al had to give him six more life from the &lt;a href=&quot;https://starcitygames.com/search/?card_name=Ball%20Lightning&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Ball Lightning&lt;/a&gt; … And still took at least eight from the Pups before he could control them. It would have profited Al much more to Plow the Pups, Passage the Ball, and enter the midgame with twenty life as he started to threaten with his own Paladins, Priests, etc.&lt;/p&gt;
&lt;p&gt;The same comparison can be made when two control-based decks slug it out. At the same PTQ, I was playing &lt;a href=&quot;https://starcitygames.com/search/?card_name=High%20Tide&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;High Tide&lt;/a&gt; against what is normally a dangerous matchup for me, CounterSliver. My opponent was running the usual array of Slivers, &lt;a href=&quot;https://starcitygames.com/search/?card_name=Worship&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Worship&lt;/a&gt;, and permission, as well as &lt;a href=&quot;https://starcitygames.com/search/?card_name=Cursed%20Scroll&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Cursed Scroll&lt;/a&gt;. He made the mistake of thinking he was the control deck.&lt;/p&gt;
&lt;p&gt;After playing a turn-2 &lt;a href=&quot;https://starcitygames.com/search/?card_name=Crystalline%20Sliver&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Crystalline Sliver&lt;/a&gt;, he followed up two turns later with &lt;a href=&quot;https://starcitygames.com/search/?card_name=Worship&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Worship&lt;/a&gt;, so I Stroked him out. (I killed him the first game with &lt;a href=&quot;https://starcitygames.com/search/?card_name=Palinchron&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Palinchron&lt;/a&gt;, and because I mostly showed him some &lt;a href=&quot;https://starcitygames.com/search/?card_name=Disrupt&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Disrupts&lt;/a&gt;, &lt;a href=&quot;https://starcitygames.com/search/?card_name=Force%20Spike&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Force Spikes&lt;/a&gt;, and card drawing, he may have thought I was more creature heavy).&lt;/p&gt;
&lt;p&gt;It doesn’t matter… He thought he was the control deck in this matchup when clearly &lt;em&gt;I&lt;/em&gt; was the control deck. I had a comparable or greater amount of permission, but where he had Slivers, I had card drawing and deck manipulation; where he had dual lands, I had &lt;a href=&quot;https://starcitygames.com/search/?card_name=Thawing%20Glaciers&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Thawing Glaciers&lt;/a&gt;. My Thaws were going to insure that I never missed a land drop. I had already housed a couple of his &lt;a href=&quot;https://starcitygames.com/search/?card_name=Brainstorm&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Brainstorms&lt;/a&gt; with &lt;a href=&quot;https://starcitygames.com/search/?card_name=Disrupt&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Disrupt&lt;/a&gt;. This means that I was going to win the long game every single time.&lt;/p&gt;
&lt;p&gt;His job, therefore, was to kill me before I killed him. The normal formula is to play some decent-sized Slivers (two power or more) attacking every turn and leaving mana open to try to counter whatever the opposing blue deck does that might be threatening (you know, a &lt;a href=&quot;https://starcitygames.com/search/?card_name=Wrath%20of%20God&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Wrath of God&lt;/a&gt;, an &lt;a href=&quot;https://starcitygames.com/search/?card_name=Engineered%20Plague&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Engineered Plague&lt;/a&gt;, or in this case the &lt;a href=&quot;https://starcitygames.com/search/?card_name=High%20Tide&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;High Tide&lt;/a&gt; finishing combo). First of all, he probably should have tried to threaten me more aggressively: only one Crystalline gives me a lot of turns of Thawing and card-drawing. Secondly, tapping out is the death knell: I didn’t even have to waste a &lt;a href=&quot;https://starcitygames.com/search/?card_name=Turnabout&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Turnabout&lt;/a&gt; on him.&lt;/p&gt;
&lt;p&gt;In similar deck vs. similar deck matchups, there are a couple of things that you want to look at to figure out what role to play:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;1. Who has more damage? Usually he has to be the beatdown deck.&lt;/li&gt;
&lt;li&gt;2. Who has more removal? Usually he has to be the control deck.&lt;/li&gt;
&lt;li&gt;3. Who has more permission and card drawing? Almost always he has to be the control deck.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you are the beatdown deck, you have to kill your opponent faster than he can kill you. If you are the control deck, you have to weather the early beatdown and get into a position where you can gain card advantage.&lt;/p&gt;
&lt;p&gt;For an example of correctly determining who is the beatdown deck and who is the control deck, look at the Sligh vs. Sligh match between Price and Pacifico at the top 8 of the 1998 U.S. Nationals. Although on the surface, the two players seem to be playing very similar decks, there are major design differences:&lt;/p&gt;
&lt;p&gt;Dave’s deck was running more &lt;a href=&quot;https://starcitygames.com/search/?card_name=Cursed%20Scroll&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Cursed Scrolls&lt;/a&gt; than Pacifico’s, and he also had &lt;a href=&quot;https://starcitygames.com/search/?card_name=Hammer%20of%20Bogardan&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Hammer of Bogardan&lt;/a&gt; and &lt;a href=&quot;https://starcitygames.com/search/?card_name=Fireslinger&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Fireslinger&lt;/a&gt;. His only real beatdown was &lt;a href=&quot;https://starcitygames.com/search/?card_name=Jackal%20Pup&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Jackal Pup&lt;/a&gt; and &lt;a href=&quot;https://starcitygames.com/search/?card_name=Ball%20Lightning&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Ball Lightning&lt;/a&gt; – the rest of the deck was more control and utility oriented.&lt;/p&gt;
&lt;p&gt;Pacifico’s deck was much more damage-oriented… It was based around attacking and celerity creatures instead of dedicated removal. In addition to &lt;a href=&quot;https://starcitygames.com/search/?card_name=Jackal%20Pup&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Jackal Pup&lt;/a&gt; and &lt;a href=&quot;https://starcitygames.com/search/?card_name=Ball%20Lightning&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Ball Lightning&lt;/a&gt;, he had &lt;a href=&quot;https://starcitygames.com/search/?card_name=Goblin%20Vandal&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Goblin Vandal&lt;/a&gt;, &lt;a href=&quot;https://starcitygames.com/search/?card_name=Mogg%20Flunkies&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Mogg Flunkies&lt;/a&gt;, Suq’ata Lancer, and &lt;a href=&quot;https://starcitygames.com/search/?card_name=Viashino%20Sandstalker&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Viashino Sandstalker&lt;/a&gt;. Furthermore, Pacifico’s deck lacked &lt;a href=&quot;https://starcitygames.com/search/?card_name=Fireslinger&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Fireslinger&lt;/a&gt; and &lt;a href=&quot;https://starcitygames.com/search/?card_name=Hammer%20of%20Bogardan&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Hammer of Bogardan&lt;/a&gt;, and ran only three &lt;a href=&quot;https://starcitygames.com/search/?card_name=Cursed%20Scroll&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Cursed Scrolls&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While Dave’s deck could definitely get a quick start, in this matchup, his deck was the control deck, set up for the long game. In one duel, Dave just played land and Scrolls and did very little else. He started by removing Pacifico’s creatures with blocks or Bolts, and then Scroll-locked him, gained a little card advantage, and finished the game.&lt;/p&gt;
&lt;p&gt;Had Dave tried to race Pacifico, he might not have won. When two players are just blindly throwing their creatures into one another, the one with more damage-oriented cards is going to win the race (but I figure we expect good Sligh play from the King of Red).&lt;/p&gt;
&lt;p&gt;Finally, think about the Suicide Black vs. Sligh matchup. These are both very fast beatdown decks. Sligh invariably wins.&lt;/p&gt;
&lt;p&gt;Which deck has more damage? Suicide Black. It runs many high power-to-cost creatures, like &lt;a href=&quot;https://starcitygames.com/search/?card_name=Carnophage&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Carnophage&lt;/a&gt;, &lt;a href=&quot;https://starcitygames.com/search/?card_name=Sarcomancy&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Sarcomancy&lt;/a&gt;, and sometimes &lt;a href=&quot;https://starcitygames.com/search/?card_name=Flesh%20Reaver&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Flesh Reaver&lt;/a&gt;. Sometimes it has stuff like &lt;a href=&quot;https://starcitygames.com/search/?card_name=Hatred&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Hatred&lt;/a&gt;. It damages even itself.&lt;/p&gt;
&lt;p&gt;Which deck has more removal? Sligh. If Suicide Black even runs &lt;a href=&quot;https://starcitygames.com/search/?card_name=Cursed%20Scroll&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Cursed Scrolls&lt;/a&gt;, the Sligh deck can invariably match them. Moreover, the Sligh deck has not just weenies, but Bolts.&lt;/p&gt;
&lt;p&gt;Though Sligh is very fast (goldfish around turn 4), Suicide Black can goldfish on turn 2 or 3 depending on the version and the Ritual draw. Clearly, the Suicide Black deck has to be the beatdown deck and the Sligh deck has to be the control deck. However, Suicide Black &lt;em&gt;can’t afford&lt;/em&gt; to be the beatdown deck. It can’t lay many of its clocks, especially &lt;a href=&quot;https://starcitygames.com/search/?card_name=Sarcomancy&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Sarcomancy&lt;/a&gt; or &lt;a href=&quot;https://starcitygames.com/search/?card_name=Flesh%20Reaver&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Flesh Reaver&lt;/a&gt;, because the Sligh deck has so many bolts. It can almost never cast a &lt;a href=&quot;https://starcitygames.com/search/?card_name=Hatred&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Hatred&lt;/a&gt;, for fear of auto-loss to an &lt;a href=&quot;https://starcitygames.com/search/?card_name=Incinerate&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Incinerate&lt;/a&gt;. So if it can’t really beat down, the Suicide Black deck has to try to be the control deck.&lt;/p&gt;
&lt;p&gt;Anyone who has ever witnessed this matchup (at least when the Sligh deck gets a decent draw) knows how well control-oriented Suicide Black turns out.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Misassignment of Role = Game Loss.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After sideboarding, the Suicide Black deck has traditionally done &lt;em&gt;much&lt;/em&gt; better. By taking out a lot of its”damage myself” cards for creature removal and life gaining, it can play the control role more adequately, and has a much improved (if not great) chance of winning.&lt;/p&gt;
&lt;p&gt;Cabal Rogue&lt;/p&gt;
&lt;p&gt;Team &lt;a href=&quot;https://starcitygames.com/search/?card_name=Discovery&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Discovery&lt;/a&gt; &lt;a href=&quot;https://starcitygames.com/search/?card_name=Channel&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Channel&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;mailto:madmanpoet@yahoo.com&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;madmanpoet@yahoo.com&lt;/a&gt;&lt;/p&gt; ]]></description>
    <pubDate>Tue, 05 May 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>ocaml guideline</title>
    <link>https://garden.linusboyle.cn/idea/ocaml-guideline</link>
    <guid>https://garden.linusboyle.cn/idea/ocaml-guideline</guid>
    <description><![CDATA[ &lt;h2 id=&quot;forbidden-feature&quot;&gt;FORBIDDEN FEATURE&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#forbidden-feature&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;NEVER use Obj.magic: Breaks type safety. There is always a better solution.&lt;/li&gt;
&lt;li&gt;There is no place for the double semicolon (&lt;code&gt;;;&lt;/code&gt;) in OCaml source code. It is used only interactively in the OCaml toplevel (REPL).&lt;/li&gt;
&lt;li&gt;Do not open modules globally. Default to use fully qualified names. Opening a module locally (e.g. &lt;code&gt;let open...&lt;/code&gt;) is fine. Introduce aliases if needed.&lt;/li&gt;
&lt;li&gt;Do not use the OCaml object/class system. Use modules instead.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;red-flags&quot;&gt;Red Flags&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#red-flags&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Most code does not require references. Introducing them should be well justified. In particular, using references to implement loops and similar local control flow is probably avoidable.&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;!=&lt;/code&gt; and &lt;code&gt;==&lt;/code&gt; for equality is probably wrong and you should use &lt;code&gt;&amp;#x3C;&gt;&lt;/code&gt; and &lt;code&gt;=&lt;/code&gt; instead, unless it is performance-oriented code that needs pointer equality.&lt;/li&gt;
&lt;li&gt;Make scoping explicit in constructs like &lt;code&gt;if&lt;/code&gt; and &lt;code&gt;match&lt;/code&gt;. A statement sequence inside an &lt;code&gt;if&lt;/code&gt; or &lt;code&gt;else&lt;/code&gt; branch must be grouped by &lt;code&gt;begin&lt;/code&gt; / &lt;code&gt;end&lt;/code&gt; or parentheses to be governed by the guard. The danger of not realising what code is governed by an if-expression is exasperated by incorrect indentation and by incremental changes to existing code.&lt;/li&gt;
&lt;li&gt;Two basic strategies for error handling exist: using exceptions, or the &lt;code&gt;Result.result&lt;/code&gt; type. The latter has the advantage of making error handling explicit in the types of functions whereas exceptions are not tracked by the type system. If not clear, prefer &lt;code&gt;Result&lt;/code&gt; over exception.&lt;/li&gt;
&lt;li&gt;Beware! A while loop is usually wrong, unless its loop invariant has been explicitly written.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;best-practices&quot;&gt;Best Practices&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#best-practices&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Purely functional code is easiest to test. Therefore code should be as functional as possible and imperative code minimised.&lt;/li&gt;
&lt;li&gt;Factor out snippets of repeated code by defining them in separate functions.&lt;/li&gt;
&lt;li&gt;The function’s usage must appear in the module’s interface that exports it, not in the program that implements it. Choose comments as in the OCaml system’s interface modules, which will subsequently automatically extract the documentation of the interface module if necessary.&lt;/li&gt;
&lt;li&gt;Use Assertions. Use assertions as much as possible, as they let you avoid verbose comments while allowing a useful verification upon execution.&lt;/li&gt;
&lt;li&gt;You must subdivide your programs into coherent modules. For each module, you must explicitly write an interface. For each interface, you must document the things defined by the module: functions, types, exceptions, etc.&lt;/li&gt;
&lt;li&gt;Prefer: Option.map, Option.bind, Option.value, Result.map, Result.bind over pattern matching&lt;/li&gt;
&lt;li&gt;You must fix every compiler warning, especially about pattern matching.&lt;/li&gt;
&lt;li&gt;Prefer monads over nested pattern matching.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;indentation-and-line-length&quot;&gt;Indentation and Line Length&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#indentation-and-line-length&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Indentation must always reflect the logic of a program.&lt;/li&gt;
&lt;li&gt;In existing code, adopt the existing style for indentation: tabs or spaces.&lt;/li&gt;
&lt;li&gt;Line length should not exceed 80 characters. Break up long lines in new code in particular.&lt;/li&gt;
&lt;li&gt;Most OCaml code bases use 2 spaces per indentation level.&lt;/li&gt;
&lt;li&gt;When making changes ensure that indentation is still correct after your change, re-indenting as necessary, but not excessively.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;naming-conventions&quot;&gt;Naming Conventions&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#naming-conventions&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cases and Names matter in OCaml. The following guidelines MUST be enforced.&lt;/p&gt;


















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Element&lt;/th&gt;&lt;th&gt;Convention&lt;/th&gt;&lt;th&gt;Example&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Files&lt;/td&gt;&lt;td&gt;&lt;code&gt;PascalCase&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;UserProfile.ml&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Modules&lt;/td&gt;&lt;td&gt;&lt;code&gt;PascalCase&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;UserProfile&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Module Types&lt;/td&gt;&lt;td&gt;&lt;code&gt;ALLCAPS&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;module type QUEUE&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Constructors&lt;/td&gt;&lt;td&gt;&lt;code&gt;PascalCase&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;type tree = Node of int&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Types&lt;/td&gt;&lt;td&gt;&lt;code&gt;snake_case&lt;/code&gt;, primary type is &lt;code&gt;t&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;type user_profile&lt;/code&gt;, &lt;code&gt;type t&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Type Variables&lt;/td&gt;&lt;td&gt;&lt;code&gt;&#039;snake_case&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;&#039;a&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Values and Functions&lt;/td&gt;&lt;td&gt;&lt;code&gt;snake_case&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;find_user&lt;/code&gt;, &lt;code&gt;create_channel&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Record Fields&lt;/td&gt;&lt;td&gt;&lt;code&gt;snake_case&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;type person = { first_name : string; age : int }&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;General considerations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Local names can be short, type variables very short. In general, the length of a name should be proportional to the size of its scope.&lt;/li&gt;
&lt;li&gt;Prefer short, but self-describing names in public interfaces.&lt;/li&gt;
&lt;li&gt;Use scoping (&lt;code&gt;let&lt;/code&gt;, &lt;code&gt;struct&lt;/code&gt;) to keep the number of names in a scope small.&lt;/li&gt;
&lt;li&gt;Avoid encoding the type into a name: &lt;code&gt;x_int&lt;/code&gt; or &lt;code&gt;x_opt&lt;/code&gt; is usually not better than &lt;code&gt;x&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Avoid repeating the module name in names for types and values: &lt;code&gt;QMP.connection&lt;/code&gt; is a better name for a type than &lt;code&gt;QMP.qmp_connection&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;In a functional language like OCaml, using &lt;code&gt;get&lt;/code&gt; as part of a name is often redundant unless it involves obtaining a value from a database or file.&lt;/li&gt;
&lt;li&gt;You may see auto-generated code use the style &lt;code&gt;.mIX_case&lt;/code&gt; where &lt;code&gt;.MIX_case&lt;/code&gt; was meant, but record fields cannot start with capital letters. Avoid this style.&lt;/li&gt;
&lt;li&gt;You can use longer names for type variables if it improves clarity, e.g. for phantom types.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;scoping&quot;&gt;Scoping&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#scoping&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use the module system to group values. It’s quite common to define simple values that belong together and to indicate this in their names:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let option_debug     = false
let option_verbosity = High
let option_log       = stdout
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is better to let the module system do the work:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;module Option = struct
  let debug     = false
  let verbosity = High
  let log       = stdout
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A value can now be accessed like in &lt;code&gt;Option.debug&lt;/code&gt;. A module simply used for grouping doesn’t require an interface.&lt;/p&gt;
&lt;h2 id=&quot;order-of-declarations&quot;&gt;Order of declarations&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#order-of-declarations&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In a module, typically the following order is maintained unless dependencies force a different order or mixing declarations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Exceptions&lt;/li&gt;
&lt;li&gt;Types&lt;/li&gt;
&lt;li&gt;Modules&lt;/li&gt;
&lt;li&gt;Values&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;comments&quot;&gt;Comments&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#comments&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Comments generally go before the code they are referencing. The possible exception are declarations in interfaces (&lt;code&gt;mli&lt;/code&gt; files, signatures) and types where they can go after the declaration.&lt;/p&gt;
&lt;p&gt;Syntactically there are two kinds of comments:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;General comments, enclosed in &lt;code&gt;(*&lt;/code&gt; and &lt;code&gt;*)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Special comments (OCamlDoc), enclosed in &lt;code&gt;(**&lt;/code&gt; and &lt;code&gt;*)&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Special comments are associated with type and values in a program and treated specially by the compiler. They become available in automatically generated documentation. For the association to work, there must be no empty line between a special comment and the element they are associated with.&lt;/p&gt;
&lt;p&gt;Code should always be as clear as possible but that clarity cannot always convey the reason behind a design. Comments have the role to provide it: the why.&lt;/p&gt;
&lt;h3 id=&quot;what-to-comment&quot;&gt;What to Comment&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#what-to-comment&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The purpose of a module or functor&lt;/li&gt;
&lt;li&gt;The purpose of a value or function in a signature (interface)&lt;/li&gt;
&lt;li&gt;The purpose of a type declaration or its components, if not obvious&lt;/li&gt;
&lt;li&gt;The purpose of record components and variants in types, if not obvious&lt;/li&gt;
&lt;li&gt;Unusual Algorithms and their complexity&lt;/li&gt;
&lt;li&gt;Invariants when not expressed as assertions&lt;/li&gt;
&lt;li&gt;Error handling&lt;/li&gt;
&lt;li&gt;Basic examples on how to use the library&lt;/li&gt;
&lt;li&gt;Known limitations&lt;/li&gt;
&lt;li&gt;Short introduction to the technology covered by the library, if not obvious&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;what-not-to-comment&quot;&gt;What not to Comment&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#what-not-to-comment&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Purpose of a local let binding - the name should tell it&lt;/li&gt;
&lt;li&gt;Every line in a function&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;interfaces&quot;&gt;Interfaces&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#interfaces&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Module interfaces are the best way to document and control an implementation - employ them widely.&lt;/p&gt;
&lt;p&gt;Before writing any implementation, design the &lt;code&gt;mli&lt;/code&gt; first. Clean interface &gt; clever implementation.&lt;/p&gt;
&lt;p&gt;As an exception to this rule, if your module only defines signatures then prefer using a &lt;code&gt;.ml&lt;/code&gt; file for this, otherwise either the &lt;code&gt;.mli&lt;/code&gt; would just be a duplicate of the &lt;code&gt;.ml&lt;/code&gt; file, or you’d have to use &lt;code&gt;.mli&lt;/code&gt; -only modules which don’t have good tooling support.&lt;/p&gt;
&lt;p&gt;If possible, make a type private and can only be constructed with the function provided by the module.&lt;/p&gt;
&lt;p&gt;In order of preference the interface of a module should expose:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;immutable data structures and operations on them. Note that the implementation can use mutation if this makes the implementation of the algorithm more natural, as long as it doesn’t “leak” the mutated variable by returning it or storing it outside local variables&lt;/li&gt;
&lt;li&gt;idempotent API calls. If the nature of the API requires mutation (e.g. a database) make it idempotent. The reason is that network/RPC calls may get interrupted before getting an answer, and the caller may not know whether the call succeeded or not, so it can just retry. If you make the retry a no-op it simplifies the logic on both sides.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;monads&quot;&gt;Monads&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#monads&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;ocaml&quot; data-theme=&quot;github-light github-dark&quot;&gt;&lt;code data-language=&quot;ocaml&quot; data-theme=&quot;github-light github-dark&quot; style=&quot;display: grid;&quot;&gt;&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-light-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold&quot;&gt;(* Before - nested matches *)&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;match fetch_user id with&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;| Ok user -&gt; (match fetch_perms user with Ok p -&gt; Ok (user, p) | Error e -&gt; Error e)&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;| Error e -&gt; Error e&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt; &lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-light-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold&quot;&gt;(* After *)&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-light-text-decoration:underline;--shiki-dark:#F97583;--shiki-dark-text-decoration:underline&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#DBEDFF&quot;&gt; open&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; Result&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Syntax&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; in&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-light-text-decoration:underline;--shiki-dark:#F97583;--shiki-dark-text-decoration:underline&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;* user = fetch_user id in&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;let+ perms = fetch_perms user in&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-light-text-decoration:underline;--shiki-dark:#79B8FF;--shiki-dark-text-decoration:underline&quot;&gt;user&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#DBEDFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-light-text-decoration:underline;--shiki-dark:#79B8FF;--shiki-dark-text-decoration:underline&quot;&gt; perms&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt; ]]></description>
    <pubDate>Sun, 03 May 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>Conventional Commits</title>
    <link>https://garden.linusboyle.cn/source/clipped/Conventional-Commits</link>
    <guid>https://garden.linusboyle.cn/source/clipped/Conventional-Commits</guid>
    <description><![CDATA[ &lt;h2 id=&quot;conventional-commits-100&quot;&gt;Conventional Commits 1.0.0&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#conventional-commits-100&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#summary&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Conventional Commits specification is a lightweight convention on top of commit messages. It provides an easy set of rules for creating an explicit commit history; which makes it easier to write automated tools on top of. This convention dovetails with &lt;a href=&quot;http://semver.org/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;SemVer&lt;/a&gt;, by describing the features, fixes, and breaking changes made in commit messages.&lt;/p&gt;
&lt;p&gt;The commit message should be structured as follows:&lt;/p&gt;
&lt;hr&gt;
&lt;pre&gt;&lt;code&gt;&amp;#x3C;type&gt;[optional scope]: &amp;#x3C;description&gt;

[optional body]

[optional footer(s)]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;p&gt;The commit contains the following structural elements, to communicate intent to the consumers of your library:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;fix:&lt;/strong&gt; a commit of the &lt;em&gt;type&lt;/em&gt; &lt;code&gt;fix&lt;/code&gt; patches a bug in your codebase (this correlates with &lt;a href=&quot;http://semver.org/#summary&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;PATCH&lt;/code&gt;&lt;/a&gt; in Semantic Versioning).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;feat:&lt;/strong&gt; a commit of the &lt;em&gt;type&lt;/em&gt; &lt;code&gt;feat&lt;/code&gt; introduces a new feature to the codebase (this correlates with &lt;a href=&quot;http://semver.org/#summary&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;MINOR&lt;/code&gt;&lt;/a&gt; in Semantic Versioning).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BREAKING CHANGE:&lt;/strong&gt; a commit that has a footer &lt;code&gt;BREAKING CHANGE:&lt;/code&gt;, or appends a &lt;code&gt;!&lt;/code&gt; after the type/scope, introduces a breaking API change (correlating with &lt;a href=&quot;http://semver.org/#summary&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;MAJOR&lt;/code&gt;&lt;/a&gt; in Semantic Versioning). A BREAKING CHANGE can be part of commits of any &lt;em&gt;type&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;types&lt;/em&gt; other than &lt;code&gt;fix:&lt;/code&gt; and &lt;code&gt;feat:&lt;/code&gt; are allowed, for example &lt;a href=&quot;https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;@commitlint/config-conventional&lt;/a&gt; (based on the &lt;a href=&quot;https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Angular convention&lt;/a&gt;) recommends &lt;code&gt;build:&lt;/code&gt;, &lt;code&gt;chore:&lt;/code&gt;, &lt;code&gt;ci:&lt;/code&gt;, &lt;code&gt;docs:&lt;/code&gt;, &lt;code&gt;style:&lt;/code&gt;, &lt;code&gt;refactor:&lt;/code&gt;, &lt;code&gt;perf:&lt;/code&gt;, &lt;code&gt;test:&lt;/code&gt;, and others.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;footers&lt;/em&gt; other than &lt;code&gt;BREAKING CHANGE: &amp;#x3C;description&gt;&lt;/code&gt; may be provided and follow a convention similar to &lt;a href=&quot;https://git-scm.com/docs/git-interpret-trailers&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;git trailer format&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Additional types are not mandated by the Conventional Commits specification, and have no implicit effect in Semantic Versioning (unless they include a BREAKING CHANGE). A scope may be provided to a commit’s type, to provide additional contextual information and is contained within parenthesis, e.g., &lt;code&gt;feat(parser): add ability to parse arrays&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;examples&quot;&gt;Examples&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#examples&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;commit-message-with-description-and-breaking-change-footer&quot;&gt;Commit message with description and breaking change footer&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#commit-message-with-description-and-breaking-change-footer&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;feat: allow provided config object to extend other configs

BREAKING CHANGE: \`extends\` key in config file is now used for extending other config files
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;commit-message-with-to-draw-attention-to-breaking-change&quot;&gt;Commit message with! to draw attention to breaking change&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#commit-message-with-to-draw-attention-to-breaking-change&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;feat!: send an email to the customer when a product is shipped
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;commit-message-with-scope-and-to-draw-attention-to-breaking-change&quot;&gt;Commit message with scope and! to draw attention to breaking change&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#commit-message-with-scope-and-to-draw-attention-to-breaking-change&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;feat(api)!: send an email to the customer when a product is shipped
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;commit-message-with-both-and-breaking-change-footer&quot;&gt;Commit message with both! and BREAKING CHANGE footer&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#commit-message-with-both-and-breaking-change-footer&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;feat!: drop support for Node 6

BREAKING CHANGE: use JavaScript features not available in Node 6.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;commit-message-with-no-body&quot;&gt;Commit message with no body&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#commit-message-with-no-body&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;docs: correct spelling of CHANGELOG
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;commit-message-with-scope&quot;&gt;Commit message with scope&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#commit-message-with-scope&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;feat(lang): add Polish language
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;commit-message-with-multi-paragraph-body-and-multiple-footers&quot;&gt;Commit message with multi-paragraph body and multiple footers&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#commit-message-with-multi-paragraph-body-and-multiple-footers&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;fix: prevent racing of requests

Introduce a request id and a reference to latest request. Dismiss
incoming responses other than from latest request.

Remove timeouts which were used to mitigate the racing issue but are
obsolete now.

Reviewed-by: Z
Refs: #123
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;specification&quot;&gt;Specification&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#specification&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in &lt;a href=&quot;https://www.ietf.org/rfc/rfc2119.txt&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;RFC 2119&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Commits MUST be prefixed with a type, which consists of a noun, &lt;code&gt;feat&lt;/code&gt;, &lt;code&gt;fix&lt;/code&gt;, etc., followed by the OPTIONAL scope, OPTIONAL &lt;code&gt;!&lt;/code&gt;, and REQUIRED terminal colon and space.&lt;/li&gt;
&lt;li&gt;The type &lt;code&gt;feat&lt;/code&gt; MUST be used when a commit adds a new feature to your application or library.&lt;/li&gt;
&lt;li&gt;The type &lt;code&gt;fix&lt;/code&gt; MUST be used when a commit represents a bug fix for your application.&lt;/li&gt;
&lt;li&gt;A scope MAY be provided after a type. A scope MUST consist of a noun describing a section of the codebase surrounded by parenthesis, e.g., &lt;code&gt;fix(parser):&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;A description MUST immediately follow the colon and space after the type/scope prefix. The description is a short summary of the code changes, e.g., &lt;em&gt;fix: array parsing issue when multiple spaces were contained in string&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;A longer commit body MAY be provided after the short description, providing additional contextual information about the code changes. The body MUST begin one blank line after the description.&lt;/li&gt;
&lt;li&gt;A commit body is free-form and MAY consist of any number of newline separated paragraphs.&lt;/li&gt;
&lt;li&gt;One or more footers MAY be provided one blank line after the body. Each footer MUST consist of a word token, followed by either a &lt;code&gt;:&amp;#x3C;space&gt;&lt;/code&gt; or &lt;code&gt;&amp;#x3C;space&gt;#&lt;/code&gt; separator, followed by a string value (this is inspired by the &lt;a href=&quot;https://git-scm.com/docs/git-interpret-trailers&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;git trailer convention&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;A footer’s token MUST use &lt;code&gt;-&lt;/code&gt; in place of whitespace characters, e.g., &lt;code&gt;Acked-by&lt;/code&gt; (this helps differentiate the footer section from a multi-paragraph body). An exception is made for &lt;code&gt;BREAKING CHANGE&lt;/code&gt;, which MAY also be used as a token.&lt;/li&gt;
&lt;li&gt;A footer’s value MAY contain spaces and newlines, and parsing MUST terminate when the next valid footer token/separator pair is observed.&lt;/li&gt;
&lt;li&gt;Breaking changes MUST be indicated in the type/scope prefix of a commit, or as an entry in the footer.&lt;/li&gt;
&lt;li&gt;If included as a footer, a breaking change MUST consist of the uppercase text BREAKING CHANGE, followed by a colon, space, and description, e.g., &lt;em&gt;BREAKING CHANGE: environment variables now take precedence over config files&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;If included in the type/scope prefix, breaking changes MUST be indicated by a &lt;code&gt;!&lt;/code&gt; immediately before the &lt;code&gt;:&lt;/code&gt;. If &lt;code&gt;!&lt;/code&gt; is used, &lt;code&gt;BREAKING CHANGE:&lt;/code&gt; MAY be omitted from the footer section, and the commit description SHALL be used to describe the breaking change.&lt;/li&gt;
&lt;li&gt;Types other than &lt;code&gt;feat&lt;/code&gt; and &lt;code&gt;fix&lt;/code&gt; MAY be used in your commit messages, e.g., &lt;em&gt;docs: update ref docs.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;The units of information that make up Conventional Commits MUST NOT be treated as case-sensitive by implementors, with the exception of BREAKING CHANGE which MUST be uppercase.&lt;/li&gt;
&lt;li&gt;BREAKING-CHANGE MUST be synonymous with BREAKING CHANGE, when used as a token in a footer.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;why-use-conventional-commits&quot;&gt;Why Use Conventional Commits&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#why-use-conventional-commits&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Automatically generating CHANGELOGs.&lt;/li&gt;
&lt;li&gt;Automatically determining a semantic version bump (based on the types of commits landed).&lt;/li&gt;
&lt;li&gt;Communicating the nature of changes to teammates, the public, and other stakeholders.&lt;/li&gt;
&lt;li&gt;Triggering build and publish processes.&lt;/li&gt;
&lt;li&gt;Making it easier for people to contribute to your projects, by allowing them to explore a more structured commit history.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;faq&quot;&gt;FAQ&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#faq&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;how-should-i-deal-with-commit-messages-in-the-initial-development-phase&quot;&gt;How should I deal with commit messages in the initial development phase?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#how-should-i-deal-with-commit-messages-in-the-initial-development-phase&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We recommend that you proceed as if you’ve already released the product. Typically &lt;em&gt;somebody&lt;/em&gt;, even if it’s your fellow software developers, is using your software. They’ll want to know what’s fixed, what breaks etc.&lt;/p&gt;
&lt;h3 id=&quot;are-the-types-in-the-commit-title-uppercase-or-lowercase&quot;&gt;Are the types in the commit title uppercase or lowercase?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#are-the-types-in-the-commit-title-uppercase-or-lowercase&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Any casing may be used, but it’s best to be consistent.&lt;/p&gt;
&lt;h3 id=&quot;what-do-i-do-if-the-commit-conforms-to-more-than-one-of-the-commit-types&quot;&gt;What do I do if the commit conforms to more than one of the commit types?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#what-do-i-do-if-the-commit-conforms-to-more-than-one-of-the-commit-types&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Go back and make multiple commits whenever possible. Part of the benefit of Conventional Commits is its ability to drive us to make more organized commits and PRs.&lt;/p&gt;
&lt;h3 id=&quot;doesnt-this-discourage-rapid-development-and-fast-iteration&quot;&gt;Doesn’t this discourage rapid development and fast iteration?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#doesnt-this-discourage-rapid-development-and-fast-iteration&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It discourages moving fast in a disorganized way. It helps you be able to move fast long term across multiple projects with varied contributors.&lt;/p&gt;
&lt;h3 id=&quot;might-conventional-commits-lead-developers-to-limit-the-type-of-commits-they-make-because-theyll-be-thinking-in-the-types-provided&quot;&gt;Might Conventional Commits lead developers to limit the type of commits they make because they’ll be thinking in the types provided?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#might-conventional-commits-lead-developers-to-limit-the-type-of-commits-they-make-because-theyll-be-thinking-in-the-types-provided&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Conventional Commits encourages us to make more of certain types of commits such as fixes. Other than that, the flexibility of Conventional Commits allows your team to come up with their own types and change those types over time.&lt;/p&gt;
&lt;h3 id=&quot;how-does-this-relate-to-semver&quot;&gt;How does this relate to SemVer?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#how-does-this-relate-to-semver&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;fix&lt;/code&gt; type commits should be translated to &lt;code&gt;PATCH&lt;/code&gt; releases. &lt;code&gt;feat&lt;/code&gt; type commits should be translated to &lt;code&gt;MINOR&lt;/code&gt; releases. Commits with &lt;code&gt;BREAKING CHANGE&lt;/code&gt; in the commits, regardless of type, should be translated to &lt;code&gt;MAJOR&lt;/code&gt; releases.&lt;/p&gt;
&lt;h3 id=&quot;how-should-i-version-my-extensions-to-the-conventional-commits-specification-eg-jameswomackconventional-commit-spec&quot;&gt;How should I version my extensions to the Conventional Commits Specification, e.g. @jameswomack/conventional-commit-spec?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#how-should-i-version-my-extensions-to-the-conventional-commits-specification-eg-jameswomackconventional-commit-spec&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We recommend using SemVer to release your own extensions to this specification (and encourage you to make these extensions!)&lt;/p&gt;
&lt;h3 id=&quot;what-do-i-do-if-i-accidentally-use-the-wrong-commit-type&quot;&gt;What do I do if I accidentally use the wrong commit type?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#what-do-i-do-if-i-accidentally-use-the-wrong-commit-type&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id=&quot;when-you-used-a-type-thats-of-the-spec-but-not-the-correct-type-eg-fix-instead-of-feat&quot;&gt;When you used a type that’s of the spec but not the correct type, e.g. fix instead of feat&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#when-you-used-a-type-thats-of-the-spec-but-not-the-correct-type-eg-fix-instead-of-feat&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Prior to merging or releasing the mistake, we recommend using &lt;code&gt;git rebase -i&lt;/code&gt; to edit the commit history. After release, the cleanup will be different according to what tools and processes you use.&lt;/p&gt;
&lt;h4 id=&quot;when-you-used-a-type-not-of-the-spec-eg-feet-instead-of-feat&quot;&gt;When you used a type not of the spec, e.g. feet instead of feat&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#when-you-used-a-type-not-of-the-spec-eg-feet-instead-of-feat&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In a worst case scenario, it’s not the end of the world if a commit lands that does not meet the Conventional Commits specification. It simply means that commit will be missed by tools that are based on the spec.&lt;/p&gt;
&lt;h3 id=&quot;do-all-my-contributors-need-to-use-the-conventional-commits-specification&quot;&gt;Do all my contributors need to use the Conventional Commits specification?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#do-all-my-contributors-need-to-use-the-conventional-commits-specification&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;No! If you use a squash based workflow on Git lead maintainers can clean up the commit messages as they’re merged—adding no workload to casual committers. A common workflow for this is to have your git system automatically squash commits from a pull request and present a form for the lead maintainer to enter the proper git commit message for the merge.&lt;/p&gt;
&lt;h3 id=&quot;how-does-conventional-commits-handle-revert-commits&quot;&gt;How does Conventional Commits handle revert commits?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#how-does-conventional-commits-handle-revert-commits&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Reverting code can be complicated: are you reverting multiple commits? if you revert a feature, should the next release instead be a patch?&lt;/p&gt;
&lt;p&gt;Conventional Commits does not make an explicit effort to define revert behavior. Instead we leave it to tooling authors to use the flexibility of &lt;em&gt;types&lt;/em&gt; and &lt;em&gt;footers&lt;/em&gt; to develop their logic for handling reverts.&lt;/p&gt;
&lt;p&gt;One recommendation is to use the &lt;code&gt;revert&lt;/code&gt; type, and a footer that references the commit SHAs that are being reverted:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;revert: let us never again speak of the noodle incident

Refs: 676104e, a215868
&lt;/code&gt;&lt;/pre&gt; ]]></description>
    <pubDate>Thu, 30 Apr 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>Semantic Versioning 2.0.0</title>
    <link>https://garden.linusboyle.cn/source/clipped/Semantic-Versioning-2.0.0</link>
    <guid>https://garden.linusboyle.cn/source/clipped/Semantic-Versioning-2.0.0</guid>
    <description><![CDATA[ &lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/ar/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;العربية (ar)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/bg/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Български (bg)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/bn/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;বাংলা (bn)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/ca/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;català (ca)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/cs/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;čeština (cs)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/da/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Dansk (da)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/de/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Deutsch (de)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/el/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Ελληνικά (el)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;English (en)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/es/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;español (es)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/fa/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;فارسی (fa)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/fr/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;français (fr)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/he/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;עברית (he)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/hin/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;हिन्दी (hin)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/hr/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;hrvatski (hr)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/hu/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;magyar (hu)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/hy/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Հայերեն (hy)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/id/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Bahasa Indonesia (id)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/it/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;italiano (it)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/ja/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;日本語 (ja)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/ka/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;ქართული (ka)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/kab/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;taqbaylit (kab)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/ko/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;한국어 (ko)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/nl/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Nederlands (nl)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/pl/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;polski (pl)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/pt-BR/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;português brasileiro (pt-BR)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/ru/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;pyccкий (ru)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/sk/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;slovensky (sk)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/sl/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;slovenščina (sl)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/sr-Cyrl/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;српски (sr-Cyrl)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/sr-Latn/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;srpski (sr-Latn)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/sv/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;svenska (sv)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/ta/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;தமிழ் (ta)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/tr/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Türkçe (tr)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/uk/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;українська (uk)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/vi/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Tiếng Việt (vi)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/zh-CN/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;简体中文 (zh-CN)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/lang/zh-TW/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;繁體中文 (zh-TW)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/spec/v2.0.0.html&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;2.0.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/spec/v2.0.0-rc.2.html&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;2.0.0-rc.2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/spec/v2.0.0-rc.1.html&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;2.0.0-rc.1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/spec/v1.0.0.html&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;1.0.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/spec/v1.0.0-beta.html&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;1.0.0-beta&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#summary&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Given a version number MAJOR.MINOR.PATCH, increment the:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;MAJOR version when you make incompatible API changes&lt;/li&gt;
&lt;li&gt;MINOR version when you add functionality in a backward compatible manner&lt;/li&gt;
&lt;li&gt;PATCH version when you make backward compatible bug fixes&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#introduction&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the world of software management there exists a dreaded place called “dependency hell.” The bigger your system grows and the more packages you integrate into your software, the more likely you are to find yourself, one day, in this pit of despair.&lt;/p&gt;
&lt;p&gt;In systems with many dependencies, releasing new package versions can quickly become a nightmare. If the dependency specifications are too tight, you are in danger of version lock (the inability to upgrade a package without having to release new versions of every dependent package). If dependencies are specified too loosely, you will inevitably be bitten by version promiscuity (assuming compatibility with more future versions than is reasonable). Dependency hell is where you are when version lock and/or version promiscuity prevent you from easily and safely moving your project forward.&lt;/p&gt;
&lt;p&gt;As a solution to this problem, we propose a simple set of rules and requirements that dictate how version numbers are assigned and incremented. These rules are based on but not necessarily limited to pre-existing widespread common practices in use in both closed and open-source software. For this system to work, you first need to declare a public API. This may consist of documentation or be enforced by the code itself. Regardless, it is important that this API be clear and precise. Once you identify your public API, you communicate changes to it with specific increments to your version number. Consider a version format of X.Y.Z (Major.Minor.Patch). Bug fixes not affecting the API increment the patch version, backward compatible API additions/changes increment the minor version, and backward incompatible API changes increment the major version.&lt;/p&gt;
&lt;p&gt;We call this system “Semantic Versioning.” Under this scheme, version numbers and the way they change convey meaning about the underlying code and what has been modified from one version to the next.&lt;/p&gt;
&lt;h2 id=&quot;semantic-versioning-specification-semver&quot;&gt;Semantic Versioning Specification (SemVer)&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#semantic-versioning-specification-semver&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in &lt;a href=&quot;https://tools.ietf.org/html/rfc2119&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;RFC 2119&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Software using Semantic Versioning MUST declare a public API. This API could be declared in the code itself or exist strictly in documentation. However it is done, it SHOULD be precise and comprehensive.&lt;/li&gt;
&lt;li&gt;A normal version number MUST take the form X.Y.Z where X, Y, and Z are non-negative integers, and MUST NOT contain leading zeroes. X is the major version, Y is the minor version, and Z is the patch version. Each element MUST increase numerically. For instance: 1.9.0 &lt;span&gt;→&lt;/span&gt; 1.10.0 &lt;span&gt;→&lt;/span&gt; 1.11.0.&lt;/li&gt;
&lt;li&gt;Once a versioned package has been released, the contents of that version MUST NOT be modified. Any modifications MUST be released as a new version.&lt;/li&gt;
&lt;li&gt;Major version zero (0.y.z) is for initial development. Anything MAY change at any time. The public API SHOULD NOT be considered stable.&lt;/li&gt;
&lt;li&gt;Version 1.0.0 defines the public API. The way in which the version number is incremented after this release is dependent on this public API and how it changes.&lt;/li&gt;
&lt;li&gt;Patch version Z (x.y.Z | x &gt; 0) MUST be incremented if only backward compatible bug fixes are introduced. A bug fix is defined as an internal change that fixes incorrect behavior.&lt;/li&gt;
&lt;li&gt;Minor version Y (x.Y.z | x &gt; 0) MUST be incremented if new, backward compatible functionality is introduced to the public API. It MUST be incremented if any public API functionality is marked as deprecated. It MAY be incremented if substantial new functionality or improvements are introduced within the private code. It MAY include patch level changes. Patch version MUST be reset to 0 when minor version is incremented.&lt;/li&gt;
&lt;li&gt;Major version X (X.y.z | X &gt; 0) MUST be incremented if any backward incompatible changes are introduced to the public API. It MAY also include minor and patch level changes. Patch and minor versions MUST be reset to 0 when major version is incremented.&lt;/li&gt;
&lt;li&gt;A pre-release version MAY be denoted by appending a hyphen and a series of dot separated identifiers immediately following the patch version. Identifiers MUST comprise only ASCII alphanumerics and hyphens [0-9A-Za-z-]. Identifiers MUST NOT be empty. Numeric identifiers MUST NOT include leading zeroes. Pre-release versions have a lower precedence than the associated normal version. A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version. Examples: 1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-0.3.7, 1.0.0-x.7.z.92, 1.0.0-x-y-z.—.&lt;/li&gt;
&lt;li&gt;Build metadata MAY be denoted by appending a plus sign and a series of dot separated identifiers immediately following the patch or pre-release version. Identifiers MUST comprise only ASCII alphanumerics and hyphens [0-9A-Za-z-]. Identifiers MUST NOT be empty. Build metadata MUST be ignored when determining version precedence. Thus two versions that differ only in the build metadata, have the same precedence. Examples: 1.0.0-alpha+001, 1.0.0+20130313144700, 1.0.0-beta+exp.sha.5114f85, 1.0.0+21AF26D3----117B344092BD.&lt;/li&gt;
&lt;li&gt;Precedence refers to how versions are compared to each other when ordered.
&lt;ol&gt;
&lt;li&gt;Precedence MUST be calculated by separating the version into major, minor, patch and pre-release identifiers in that order (Build metadata does not figure into precedence).
2. Precedence is determined by the first difference when comparing each of these identifiers from left to right as follows: Major, minor, and patch versions are always compared numerically.
Example: 1.0.0 &amp;#x3C; 2.0.0 &amp;#x3C; 2.1.0 &amp;#x3C; 2.1.1.
3. When major, minor, and patch are equal, a pre-release version has lower precedence than a normal version:
Example: 1.0.0-alpha &amp;#x3C; 1.0.0.
4. Precedence for two pre-release versions with the same major, minor, and patch version MUST be determined by comparing each dot separated identifier from left to right until a difference is found as follows:
&lt;ol&gt;
&lt;li&gt;Identifiers consisting of only digits are compared numerically.
2. Identifiers with letters or hyphens are compared lexically in ASCII sort order.
3. Numeric identifiers always have lower precedence than non-numeric identifiers.
4. A larger set of pre-release fields has a higher precedence than a smaller set, if all of the preceding identifiers are equal.
Example: 1.0.0-alpha &amp;#x3C; 1.0.0-alpha.1 &amp;#x3C; 1.0.0-alpha.beta &amp;#x3C; 1.0.0-beta &amp;#x3C; 1.0.0-beta.2 &amp;#x3C; 1.0.0-beta.11 &amp;#x3C; 1.0.0-rc.1 &amp;#x3C; 1.0.0.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;backusnaur-form-grammar-for-valid-semver-versions&quot;&gt;Backus–Naur Form Grammar for Valid SemVer Versions&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#backusnaur-form-grammar-for-valid-semver-versions&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&amp;#x3C;valid semver&gt; ::= &amp;#x3C;version core&gt;
                 | &amp;#x3C;version core&gt; &quot;-&quot; &amp;#x3C;pre-release&gt;
                 | &amp;#x3C;version core&gt; &quot;+&quot; &amp;#x3C;build&gt;
                 | &amp;#x3C;version core&gt; &quot;-&quot; &amp;#x3C;pre-release&gt; &quot;+&quot; &amp;#x3C;build&gt;

&amp;#x3C;version core&gt; ::= &amp;#x3C;major&gt; &quot;.&quot; &amp;#x3C;minor&gt; &quot;.&quot; &amp;#x3C;patch&gt;

&amp;#x3C;major&gt; ::= &amp;#x3C;numeric identifier&gt;

&amp;#x3C;minor&gt; ::= &amp;#x3C;numeric identifier&gt;

&amp;#x3C;patch&gt; ::= &amp;#x3C;numeric identifier&gt;

&amp;#x3C;pre-release&gt; ::= &amp;#x3C;dot-separated pre-release identifiers&gt;

&amp;#x3C;dot-separated pre-release identifiers&gt; ::= &amp;#x3C;pre-release identifier&gt;
                                          | &amp;#x3C;pre-release identifier&gt; &quot;.&quot; &amp;#x3C;dot-separated pre-release identifiers&gt;

&amp;#x3C;build&gt; ::= &amp;#x3C;dot-separated build identifiers&gt;

&amp;#x3C;dot-separated build identifiers&gt; ::= &amp;#x3C;build identifier&gt;
                                    | &amp;#x3C;build identifier&gt; &quot;.&quot; &amp;#x3C;dot-separated build identifiers&gt;

&amp;#x3C;pre-release identifier&gt; ::= &amp;#x3C;alphanumeric identifier&gt;
                           | &amp;#x3C;numeric identifier&gt;

&amp;#x3C;build identifier&gt; ::= &amp;#x3C;alphanumeric identifier&gt;
                     | &amp;#x3C;digits&gt;

&amp;#x3C;alphanumeric identifier&gt; ::= &amp;#x3C;non-digit&gt;
                            | &amp;#x3C;non-digit&gt; &amp;#x3C;identifier characters&gt;
                            | &amp;#x3C;identifier characters&gt; &amp;#x3C;non-digit&gt;
                            | &amp;#x3C;identifier characters&gt; &amp;#x3C;non-digit&gt; &amp;#x3C;identifier characters&gt;

&amp;#x3C;numeric identifier&gt; ::= &quot;0&quot;
                       | &amp;#x3C;positive digit&gt;
                       | &amp;#x3C;positive digit&gt; &amp;#x3C;digits&gt;

&amp;#x3C;identifier characters&gt; ::= &amp;#x3C;identifier character&gt;
                          | &amp;#x3C;identifier character&gt; &amp;#x3C;identifier characters&gt;

&amp;#x3C;identifier character&gt; ::= &amp;#x3C;digit&gt;
                         | &amp;#x3C;non-digit&gt;

&amp;#x3C;non-digit&gt; ::= &amp;#x3C;letter&gt;
              | &quot;-&quot;

&amp;#x3C;digits&gt; ::= &amp;#x3C;digit&gt;
           | &amp;#x3C;digit&gt; &amp;#x3C;digits&gt;

&amp;#x3C;digit&gt; ::= &quot;0&quot;
          | &amp;#x3C;positive digit&gt;

&amp;#x3C;positive digit&gt; ::= &quot;1&quot; | &quot;2&quot; | &quot;3&quot; | &quot;4&quot; | &quot;5&quot; | &quot;6&quot; | &quot;7&quot; | &quot;8&quot; | &quot;9&quot;

&amp;#x3C;letter&gt; ::= &quot;A&quot; | &quot;B&quot; | &quot;C&quot; | &quot;D&quot; | &quot;E&quot; | &quot;F&quot; | &quot;G&quot; | &quot;H&quot; | &quot;I&quot; | &quot;J&quot;
           | &quot;K&quot; | &quot;L&quot; | &quot;M&quot; | &quot;N&quot; | &quot;O&quot; | &quot;P&quot; | &quot;Q&quot; | &quot;R&quot; | &quot;S&quot; | &quot;T&quot;
           | &quot;U&quot; | &quot;V&quot; | &quot;W&quot; | &quot;X&quot; | &quot;Y&quot; | &quot;Z&quot; | &quot;a&quot; | &quot;b&quot; | &quot;c&quot; | &quot;d&quot;
           | &quot;e&quot; | &quot;f&quot; | &quot;g&quot; | &quot;h&quot; | &quot;i&quot; | &quot;j&quot; | &quot;k&quot; | &quot;l&quot; | &quot;m&quot; | &quot;n&quot;
           | &quot;o&quot; | &quot;p&quot; | &quot;q&quot; | &quot;r&quot; | &quot;s&quot; | &quot;t&quot; | &quot;u&quot; | &quot;v&quot; | &quot;w&quot; | &quot;x&quot;
           | &quot;y&quot; | &quot;z&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;why-use-semantic-versioning&quot;&gt;Why Use Semantic Versioning?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#why-use-semantic-versioning&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is not a new or revolutionary idea. In fact, you probably do something close to this already. The problem is that “close” isn’t good enough. Without compliance to some sort of formal specification, version numbers are essentially useless for dependency management. By giving a name and clear definition to the above ideas, it becomes easy to communicate your intentions to the users of your software. Once these intentions are clear, flexible (but not too flexible) dependency specifications can finally be made.&lt;/p&gt;
&lt;p&gt;A simple example will demonstrate how Semantic Versioning can make dependency hell a thing of the past. Consider a library called “Firetruck.” It requires a Semantically Versioned package named “Ladder.” At the time that Firetruck is created, Ladder is at version 3.1.0. Since Firetruck uses some functionality that was first introduced in 3.1.0, you can safely specify the Ladder dependency as greater than or equal to 3.1.0 but less than 4.0.0. Now, when Ladder version 3.1.1 and 3.2.0 become available, you can release them to your package management system and know that they will be compatible with existing dependent software.&lt;/p&gt;
&lt;p&gt;As a responsible developer you will, of course, want to verify that any package upgrades function as advertised. The real world is a messy place; there’s nothing we can do about that but be vigilant. What you can do is let Semantic Versioning provide you with a sane way to release and upgrade packages without having to roll new versions of dependent packages, saving you time and hassle.&lt;/p&gt;
&lt;p&gt;If all of this sounds desirable, all you need to do to start using Semantic Versioning is to declare that you are doing so and then follow the rules. Link to this website from your README so others know the rules and can benefit from them.&lt;/p&gt;
&lt;h2 id=&quot;faq&quot;&gt;FAQ&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#faq&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;how-should-i-deal-with-revisions-in-the-0yz-initial-development-phase&quot;&gt;How should I deal with revisions in the 0.y.z initial development phase?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#how-should-i-deal-with-revisions-in-the-0yz-initial-development-phase&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The simplest thing to do is start your initial development release at 0.1.0 and then increment the minor version for each subsequent release.&lt;/p&gt;
&lt;h3 id=&quot;how-do-i-know-when-to-release-100&quot;&gt;How do I know when to release 1.0.0?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#how-do-i-know-when-to-release-100&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If your software is being used in production, it should probably already be 1.0.0. If you have a stable API on which users have come to depend, you should be 1.0.0. If you’re worrying a lot about backward compatibility, you should probably already be 1.0.0.&lt;/p&gt;
&lt;h3 id=&quot;doesnt-this-discourage-rapid-development-and-fast-iteration&quot;&gt;Doesn’t this discourage rapid development and fast iteration?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#doesnt-this-discourage-rapid-development-and-fast-iteration&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Major version zero is all about rapid development. If you’re changing the API every day you should either still be in version 0.y.z or on a separate development branch working on the next major version.&lt;/p&gt;
&lt;h3 id=&quot;if-even-the-tiniest-backward-incompatible-changes-to-the-public-api-require-a-major-version-bump-wont-i-end-up-at-version-4200-very-rapidly&quot;&gt;If even the tiniest backward incompatible changes to the public API require a major version bump, won’t I end up at version 42.0.0 very rapidly?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#if-even-the-tiniest-backward-incompatible-changes-to-the-public-api-require-a-major-version-bump-wont-i-end-up-at-version-4200-very-rapidly&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is a question of responsible development and foresight. Incompatible changes should not be introduced lightly to software that has a lot of dependent code. The cost that must be incurred to upgrade can be significant. Having to bump major versions to release incompatible changes means you’ll think through the impact of your changes, and evaluate the cost/benefit ratio involved.&lt;/p&gt;
&lt;h3 id=&quot;documenting-the-entire-public-api-is-too-much-work&quot;&gt;Documenting the entire public API is too much work!&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#documenting-the-entire-public-api-is-too-much-work&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It is your responsibility as a professional developer to properly document software that is intended for use by others. Managing software complexity is a hugely important part of keeping a project efficient, and that’s hard to do if nobody knows how to use your software, or what methods are safe to call. In the long run, Semantic Versioning, and the insistence on a well defined public API can keep everyone and everything running smoothly.&lt;/p&gt;
&lt;h3 id=&quot;what-do-i-do-if-i-accidentally-release-a-backward-incompatible-change-as-a-minor-version&quot;&gt;What do I do if I accidentally release a backward incompatible change as a minor version?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#what-do-i-do-if-i-accidentally-release-a-backward-incompatible-change-as-a-minor-version&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As soon as you realize that you’ve broken the Semantic Versioning spec, fix the problem and release a new minor version that corrects the problem and restores backward compatibility. Even under this circumstance, it is unacceptable to modify versioned releases. If it’s appropriate, document the offending version and inform your users of the problem so that they are aware of the offending version.&lt;/p&gt;
&lt;h3 id=&quot;what-should-i-do-if-i-update-my-own-dependencies-without-changing-the-public-api&quot;&gt;What should I do if I update my own dependencies without changing the public API?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#what-should-i-do-if-i-update-my-own-dependencies-without-changing-the-public-api&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;That would be considered compatible since it does not affect the public API. Software that explicitly depends on the same dependencies as your package should have their own dependency specifications and the author will notice any conflicts. Determining whether the change is a patch level or minor level modification depends on whether you updated your dependencies in order to fix a bug or introduce new functionality. We would usually expect additional code for the latter instance, in which case it’s obviously a minor level increment.&lt;/p&gt;
&lt;h3 id=&quot;what-if-i-inadvertently-alter-the-public-api-in-a-way-that-is-not-compliant-with-the-version-number-change-ie-the-code-incorrectly-introduces-a-major-breaking-change-in-a-patch-release&quot;&gt;What if I inadvertently alter the public API in a way that is not compliant with the version number change (i.e. the code incorrectly introduces a major breaking change in a patch release)?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#what-if-i-inadvertently-alter-the-public-api-in-a-way-that-is-not-compliant-with-the-version-number-change-ie-the-code-incorrectly-introduces-a-major-breaking-change-in-a-patch-release&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use your best judgment. If you have a huge audience that will be drastically impacted by changing the behavior back to what the public API intended, then it may be best to perform a major version release, even though the fix could strictly be considered a patch release. Remember, Semantic Versioning is all about conveying meaning by how the version number changes. If these changes are important to your users, use the version number to inform them.&lt;/p&gt;
&lt;h3 id=&quot;how-should-i-handle-deprecating-functionality&quot;&gt;How should I handle deprecating functionality?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#how-should-i-handle-deprecating-functionality&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Deprecating existing functionality is a normal part of software development and is often required to make forward progress. When you deprecate part of your public API, you should do two things: (1) update your documentation to let users know about the change, (2) issue a new minor release with the deprecation in place. Before you completely remove the functionality in a new major release there should be at least one minor release that contains the deprecation so that users can smoothly transition to the new API.&lt;/p&gt;
&lt;h3 id=&quot;does-semver-have-a-size-limit-on-the-version-string&quot;&gt;Does SemVer have a size limit on the version string?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#does-semver-have-a-size-limit-on-the-version-string&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;No, but use good judgment. A 255 character version string is probably overkill, for example. Also, specific systems may impose their own limits on the size of the string.&lt;/p&gt;
&lt;h3 id=&quot;is-v123-a-semantic-version&quot;&gt;Is “v1.2.3” a semantic version?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#is-v123-a-semantic-version&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;No, “v1.2.3” is not a semantic version. However, prefixing a semantic version with a “v” is a common way (in English) to indicate it is a version number. Abbreviating “version” as “v” is often seen with version control. Example: &lt;code&gt;git tag v1.2.3 -m &quot;Release version 1.2.3&quot;&lt;/code&gt;, in which case “v1.2.3” is a tag name and the semantic version is “1.2.3”.&lt;/p&gt;
&lt;h3 id=&quot;is-there-a-suggested-regular-expression-regex-to-check-a-semver-string&quot;&gt;Is there a suggested regular expression (RegEx) to check a SemVer string?&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There are two. One with named groups for those systems that support them (PCRE [Perl Compatible Regular Expressions, i.e. Perl, PHP and R], Python and Go).&lt;/p&gt;
&lt;p&gt;See: &lt;a href=&quot;https://regex101.com/r/Ly7O1x/3/&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;https://regex101.com/r/Ly7O1x/3/&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;^(?P&amp;#x3C;major&gt;0|[1-9]\d*)\.(?P&amp;#x3C;minor&gt;0|[1-9]\d*)\.(?P&amp;#x3C;patch&gt;0|[1-9]\d*)(?:-(?P&amp;#x3C;prerelease&gt;(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P&amp;#x3C;buildmetadata&gt;[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And one with numbered capture groups instead (so cg1 = major, cg2 = minor, cg3 = patch, cg4 = prerelease and cg5 = buildmetadata) that is compatible with ECMA Script (JavaScript), PCRE (Perl Compatible Regular Expressions, i.e. Perl, PHP and R), Python and Go.&lt;/p&gt;
&lt;p&gt;See: &lt;a href=&quot;https://regex101.com/r/vkijKf/1/&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;https://regex101.com/r/vkijKf/1/&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;about&quot;&gt;About&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#about&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Semantic Versioning specification was originally authored by &lt;a href=&quot;https://tom.preston-werner.com/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Tom Preston-Werner&lt;/a&gt;, inventor of Gravatar and cofounder of GitHub.&lt;/p&gt;
&lt;p&gt;If you’d like to leave feedback, please &lt;a href=&quot;https://github.com/semver/semver/issues&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;open an issue on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;license&quot;&gt;License&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#license&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://creativecommons.org/licenses/by/3.0/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Creative Commons ― CC BY 3.0&lt;/a&gt;&lt;/p&gt; ]]></description>
    <pubDate>Thu, 30 Apr 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>MTG</title>
    <link>https://garden.linusboyle.cn/idea/MTG</link>
    <guid>https://garden.linusboyle.cn/idea/MTG</guid>
    <description><![CDATA[ &lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../source/clipped/Who&amp;#x27;s-The-Beatdown&quot; class=&quot;internal alias&quot; data-slug=&quot;source/clipped/Who&amp;#x27;s-The-Beatdown&quot;&gt;Who’s The Beatdown&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;限制赛&quot;&gt;限制赛&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#限制赛&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;../source/clipped/Stark-Reality---Drafting-the-Hard-Way&quot; class=&quot;internal alias&quot; data-slug=&quot;source/clipped/Stark-Reality---Drafting-the-Hard-Way&quot;&gt;Stark Reality - Drafting the Hard Way&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../source/clipped/Do-the-Bots-Send-Signals&quot; class=&quot;internal alias&quot; data-slug=&quot;source/clipped/Do-the-Bots-Send-Signals&quot;&gt;Do the Bots Send Signals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../source/clipped/Learning-from-the-Best&quot; class=&quot;internal alias&quot; data-slug=&quot;source/clipped/Learning-from-the-Best&quot;&gt;Learning from the Best&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../source/clipped/Simulating-Draft-Strategies&quot; class=&quot;internal alias&quot; data-slug=&quot;source/clipped/Simulating-Draft-Strategies&quot;&gt;Simulating Draft Strategies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../source/clipped/Evaluating-Combat-Tricks-In-Limited&quot; class=&quot;internal alias&quot; data-slug=&quot;source/clipped/Evaluating-Combat-Tricks-In-Limited&quot;&gt;Evaluating Combat Tricks In Limited&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;法术力基础&quot;&gt;法术力基础&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#法术力基础&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;ref. Frank Karsten&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;主色均需要至少8点&lt;/li&gt;
&lt;li&gt;双色98基本地属于勉强能接受，最好有2个多色地（除非是有很多1费的快攻）&lt;/li&gt;
&lt;li&gt;轮抓时要考虑法术力符号&lt;/li&gt;
&lt;li&gt;避免无色地&lt;/li&gt;
&lt;li&gt;快攻几乎不混色、低费牌几乎不混&lt;/li&gt;
&lt;li&gt;混色需要3~4点来源&lt;/li&gt;
&lt;/ul&gt; ]]></description>
    <pubDate>Sat, 25 Apr 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>Simulating Draft Strategies</title>
    <link>https://garden.linusboyle.cn/source/clipped/Simulating-Draft-Strategies</link>
    <guid>https://garden.linusboyle.cn/source/clipped/Simulating-Draft-Strategies</guid>
    <description><![CDATA[ &lt;p&gt;There have been a few different styles of drafting proposed over the years. Ben Stark’s &lt;a href=&quot;https://www.channelfireball.com/article/Stark-Reality-Drafting-the-Hard-Way/397b71cd-11d4-4644-9e77-5c08846d30c0/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Drafting the Hard Way&lt;/a&gt; is the seminal article on reading signals in draft by trying to intuit what your neighbors are drafting and why that leads to better results over the long run. He also introduces the terminology of drafting “the easy way”: holding onto your first pick for dear life. A few years later, Ondřej Stráský introduced a middle ground concept in his article &lt;em&gt;Drafting the Medium Way&lt;/em&gt;, which was later reinforced by Ryan Saxe in his article &lt;a href=&quot;https://articles.starcitygames.com/premium/limited-fundamentals-maximizing-for-your-own-preferences/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Maximizing For Your Own Preferences&lt;/a&gt; and on Lords of Limited as &lt;a href=&quot;https://www.lordsoflimited.com/episodes/ryan-saxe-amp-drafting-with-preferences-episode-26&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Drafting with Preferences&lt;/a&gt;. These takes suggest leaning into a subset of archetypes in a draft, either because you know they generally result in stronger decks, or perhaps because you’re just more comfortable with them. If there are any of these articles you haven’t read, I’d strongly recommend reading them as they present very helpful concepts useful to any drafter - the descriptions I’ve provided are vast oversimplifications of the information they provide.&lt;/p&gt;
&lt;p&gt;There has been debate about which of these methods is best, and any of the authors would likely agree that it depends on many factors. When &lt;em&gt;Drafting the Hard Way&lt;/em&gt; came out, it was pretty common for most people to be drafting the “easy way”, and someone who was reading signals in the draft could often get a significant leg up on the others in their pod as a result. These days, with more draft content available than any one person could hope to consume, a lot more people are trying to read signals, and the benefit of doing so is lessened. If everyone is drafting the hard way, it becomes tough for anyone to read clear signals and can result in some weaker decks. If some people at the table are drafting with preferences towards a few decks, they can send better signals that other colors are open and wind up with stronger decks. However, if everyone believes UR to be best and leans into drafting it, those who don’t abandon ship can be left with pretty weak decks as the cards in their colors dry up. There’s a lot of interesting game theory at play here, though we won’t dive too deeply into that.&lt;/p&gt;
&lt;p&gt;Through all of these articles, everyone has theorized what impact this may have on a draft and backed it up with their overall experience. It’s easy enough to see for yourself what happens if you try to use one of these techniques in any given draft, but no one ever seals the packs back up and runs it again with a different strategy. Today, however, we’re happy to be able to actually show you what happens if you do just that! Using all the data submitted by 17Lands users, we’ve developed draft bots that can simulate different personalities for us. To see what happens in these scenarios, we’ve put them all at a table together, trying out different configurations but keeping the same set of packs through these different iterations just to see what happens!&lt;/p&gt;
&lt;h2 id=&quot;lets-run-it-back&quot;&gt;Let’s Run It Back&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#lets-run-it-back&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For each of the simulations we run through, we’ll include a visualization of what profile is in each seat, and we’ll highlight the same seat across each draft to see the impact of their and other draft personalities’ choices. “E” indicates an easy-way drafter, “H” indicates the hard-way, and “P +XY -Z” indicates a preference for colors X and Y as well as a tendency to avoid color Z. At the end, we’ll also share with you a number of other different drafts and configurations with all of the draft viewers exposed so you can explore even more for yourself. With that background in mind, let’s get to it!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.17lands.com/assets/img/posts/2020-07-28-simulating-draft-strategies/table_1.png&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.17lands.com/assets/img/posts/2020-07-28-simulating-draft-strategies/table_1.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Our first configuration pits a table full of easy-way drafters against each other. You should take a look at the draft viewer for the highlighted seat &lt;a href=&quot;https://www.17lands.com/draft/e0f7b33f46ac4531bc66e0f0db4d39d2&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;. In this case, we see the drafter take what was deemed the best common early on -&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=476096&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Grasp of Darkness&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;- over&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=456570&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Thrashing Brontodon&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=592753&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Hunter’s Edge&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;. From there, it avoids taking&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=485541&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Experimental Overload&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;because that’s pretty unlikely to be played in the same deck as a double-pipped black card and instead takes&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=389624&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Palladium Myr&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;. A couple of picks later, once&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=243210&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Walking Corpse&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;is the only remaining black card, it ventures out into another color for a strong white card in&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=485328&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Aven Gagglemaster&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;. Only when there’s only sideboard-level cards left in the pack does it venture into other colors. The results after pack one are pretty bleak, with a mix of mainly black, blue, and white cards in the pool as the person passing to our featured drafter was also in black. In packs two and three, they move more solidly into blue and are able to pick up a couple of good black cards, but overall, the draft goes pretty poorly, having never moved off of the black that wasn’t flowing.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.17lands.com/assets/img/posts/2020-07-28-simulating-draft-strategies/table_2.png&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.17lands.com/assets/img/posts/2020-07-28-simulating-draft-strategies/table_2.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Next, we use those same packs, but have all the drafters set to do it “the hard way,” including &lt;a href=&quot;https://www.17lands.com/draft/a837759759e0430f83c244bb046d03a3&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;our featured drafter&lt;/a&gt;. We can see an immediate difference in pick two, with the drafter recognizing the strength of&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=485541&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Experimental Overload&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;even though it means giving up on the&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=476096&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Grasp of Darkness&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;from pick one. If more cards for the blue-red spells deck follow, good things will result. Throughout the rest of pack one, blue and red do seem to be pretty open, so not a whole lot of bobbing and weaving is necessary after the second pick. If you look closely, though, you can even see as early as pick four the results of other drafters altering their picks as well. In the second pack, this drafter is rewarded handsomely for recognizing their lane, with the bot to their right having picked up that UR wasn’t open, passing strong cards for the deck like&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=622727&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Shipwreck Dowser&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=651871&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Goblin Wizardry&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;. Pack three rounds out with some more solid additions to the UR spells deck, leaving many options for how to best configure the deck by the end.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.17lands.com/assets/img/posts/2020-07-28-simulating-draft-strategies/table_3.png&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.17lands.com/assets/img/posts/2020-07-28-simulating-draft-strategies/table_3.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Next, we see what happens when we mix easy- and hard-way drafters at the same table. In this case, &lt;a href=&quot;https://www.17lands.com/draft/17abda3954d64b8e9dc119d30b3b18ef&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;our easy-way drafter&lt;/a&gt; doesn’t actually have as much of an option to get mixed up in blue or white and actually gets pushed pretty early on into green as their second color. The hard-way drafter passing to them better picked up that white was open, cutting off that avenue. While this draft isn’t necessarily much better or worse for our easy-way drafter, it’s still interesting to note that it winds up significantly different from the all easy-way drafting from our first scenario.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.17lands.com/assets/img/posts/2020-07-28-simulating-draft-strategies/table_4.png&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.17lands.com/assets/img/posts/2020-07-28-simulating-draft-strategies/table_4.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Lastly, we get to mix in drafting with preferences. In M21, the consensus seems to be that the Naya colors (white, red, and green) are the strongest, as they have a deep roster of commons that contribute to the aggressive plan. As such, we see what happens in &lt;a href=&quot;https://www.17lands.com/draft/19bcc3083993417994259d08c0990070&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;that same seat&lt;/a&gt; with an early preference towards these colors and a bias against black as the worst color. Perhaps unsurprisingly, we wind up with a totally different deck. The drafter forces its way into WG early on, with red not having been flowing much at all. Choices of&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=456570&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Thrashing Brontodon&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;and*&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=130489&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Quirion Dryad&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;over somewhat comparable black cards emphasize this preference. In pack two, they’re rewarded with some great cards for the deck, and even see some benefit later on in the pack with cards like&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=591449&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Daybreak Charger&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;and&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=485325&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Alpine Watchdog&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;*wheeling, which didn’t happen at all in any of our earlier drafts. While the final result isn’t the best WG deck, it certainly has the tools to rumble with the rest.&lt;/p&gt;
&lt;h2 id=&quot;more-to-explore&quot;&gt;More to Explore&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#more-to-explore&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What we’ve described here is just one set of packs, and a couple of personality configurations. For those interested, we’ve generated quite a few more scenarios for you to peruse as outlined in the table below. Each link includes the bot personality and the final colors they ended up in. The scenarios described above are pack list “A”.&lt;/p&gt;


































































































































































































































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Pack List&lt;/th&gt;&lt;th&gt;Seat 1&lt;/th&gt;&lt;th&gt;Seat 2&lt;/th&gt;&lt;th&gt;Seat 3&lt;/th&gt;&lt;th&gt;Seat 4&lt;/th&gt;&lt;th&gt;Seat 5&lt;/th&gt;&lt;th&gt;Seat 6&lt;/th&gt;&lt;th&gt;Seat 7&lt;/th&gt;&lt;th&gt;Seat 8&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;A&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/e0f7b33f46ac4531bc66e0f0db4d39d2&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (UB)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/a0e92e580d6f46e8be3d88fa1f49eb4f&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/b13277c80c9e4693bc22fcffc0abbeb5&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (RG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/ef7967df703a4fb2bd8c7f77d565547f&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (Wb)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/e7a01db64b634fa99abc7124ff85688e&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WB)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/b4e15c5a71fe4bd297cfa9c229843e71&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/51aced90307f45e7bb9ea9233d243425&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (Gb)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/05f110a397df4042ae0e10fd356eddbe&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WB)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;A&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/a837759759e0430f83c244bb046d03a3&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/f3bebdca29404c4bb02fc71d2df7f7c9&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (Gr)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/4aed614607a74c419ca01dcd45ec1cb5&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/4963cc4a613d474e80d3083865e1cc57&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (Bu)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/d19dee778e5e42b49486273cf1dfc19e&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UB)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/6189e79c0f55407c88b7829b8dafa95a&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (Rg)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/cc7e03d5549346ecad4beb22bbbcc060&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (Wg)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/f2785217166a47c28dd2e042bb8a08fe&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (WB)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;A&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/17abda3954d64b8e9dc119d30b3b18ef&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (BG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/78abd1213d1f4ff8b618f21c82dbd381&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/e870aaea43dc47818375fa1fd8bc5473&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (RG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/ce1b7ff6edc04924b4898edf0c77e4df&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (Wb)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/7ea43db0d3b040849f2fb36eb8e35133&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (Bu)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/bb58e6b9f7eb4f4d995ff43d31cf53ce&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/6a2e1de067cc4661a9397d84d8ad4cbb&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (Gr)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/d147abaef23b431ead207bf67b56450f&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (WB)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;A&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/19bcc3083993417994259d08c0990070&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P+WRG-B (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/478b85d04d0d463d93a6ff79f4e03161&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/8c63cd0f251e4adab524df4b6a1f9836&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (Gr)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/3d0d3e8313924c10820afc271157afa1&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (Bw)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/92f8acc62a3744838b9eac47da500647&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P+UR-B (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/6c361433ffb343a7a4ec2ff6333115d2&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (WB)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/dbfc07fe72fa46b28955d2414bc5240e&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (BG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/4044d14117d54360972ec12eddf583f3&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (WB)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/916165a92fbe47df90ca4ceaa722d666&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (BG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/a3e1a03b8c5c46aab465776164c5eff8&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (UB)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/6ac9b623c60140eaad601962c1af8a83&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/f24e707a3ac94768a4d5a8733e46b0b0&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (B)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/ef3404a900a64bad95661507f0cfb5f6&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (Gr)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/7ba6f12eefb7483c966cb38225b15c7f&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (W)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/18abc865d5d043c3a4f38fec32dd7c61&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/be9cfe570cad490c89f0b4fc03c21f79&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WR)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/f11cd4cc8e464cf39e0ed7ee47dfc5e9&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (BG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/baa0e3e4db584e1094fc6e35eadaa39c&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (UB)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/5da8de42c0934490ae3c43ed31ff92e8&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/48d751f183a64bde991e7364b604572f&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (B)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/1a606e6174074e3a973d5822ba072229&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (Gr)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/acdf46ea304e40cb975c89598d336df4&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (W)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/957f7cff316e4db2a0e04d76ad956b4c&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/4368a5f42baa4372acc9c02efd737220&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WR)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/375f237a55be422c8996df4afd40cd73&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (BG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/a2b1f2767dcd4dcabbf51272e457b95c&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UB)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/0f64087b16854da9bbf7ea8f265a49f6&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (WR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/51b0275333d845dbafdc776533142024&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/0c2766b19ac244a8bddd1e5f3972984d&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (Rg)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/18f495abf23b4f8c8a2f828ae089ff2a&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/d3441af633604d669749af03afd9e33b&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (Ub)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/1ceaff098eed4f7fa4499931825ec0ea&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (W)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/d66133cd0dd64610a5e8a0b66aa51a7a&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (BG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/fff0873acfa5402d9e7ef30b33816869&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/da80c01b456e4e4b9ea8ad5328b51985&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/6b44f7986d7b453391fa02be81195733&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/ad2dc27004c946a096265259602ed86f&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (UG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/33550335713c40bd9efbd8b077de4da3&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (WR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/a249069d40234826a1c384d922f33b31&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (U)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/4f3c4097e9754c438acf48187ca92e77&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (WB)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/5528675dc5db43c3b87a00884a649c01&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (B)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/f5e3d116123c47a7b3d6acd5867402b2&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (RG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/be161447c72c4e3280429ee092b77d8d&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/c7228252b42f41ba9853a3b5d7e2bd18&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (Bu)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/9db95788de9840bc8519bf08db50441f&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/36bff4dc84184dd2806754cf371507d6&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/f8863eb043c14997ad1a80ed8b2bf9c2&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (U)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/439055a6002e4d11aa0962620cdc3369&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (W)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/eb249fb2ac424561ba70c30b2f505e61&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P+WRG-B (Gr)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/1f7d9e72e9494db6af16733f63a5e9bc&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (WU)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/633bd7280d114b3ab4df0141de167ffe&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/19318276069144998ba2576d5e29993b&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UB)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/d5827ea16dee44e3ba7a418ee7e6ae0c&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P+UR-B (Ru)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/86a5c2f51cbe499ab50c5e35d472bb40&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/08b66de0134e45c4b3564fed7ca91ad6&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (U)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/8f03d95887f04da9aa51430cd4a375b6&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (WB)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/d472958ecad4498698fd52439522e140&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P+WRG-B (BG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/3dad9e17694548d0a0a264331bce349c&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P+UR-B (UB)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/95e818b5b1744f42bb2210a776c16d9b&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P+WRG-B (WR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/ec3e9daffcbd45fba833179ba6eb4142&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P+UR-B (UB)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/3eb7edfd54bc41dd99cf79c79e39d881&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (Rg)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/79f0598931f54883a13eb872754461d2&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P+WRG-B (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/3a3aa739a2fd4f22831583b435a0f20a&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P+UR-B (U)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/47394743743f47e5ac195cd23522d382&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P+WRG-B (WR)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/9635674acb7a43cfa332b628dab29a17&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/40d7edd5620c4e95b6859c9f9d3b0ef6&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (U)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/472c8d7a7e3f415782ce0f66e0e0ea3a&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/6517dfa044e44a448328026c76a2cdec&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (Rg)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/7622e42675ad44d48205a4d86000a599&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (Ub)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/181745c05e314f71b6d9d5d7f5023385&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/0f262bcc0830442ebb58355a28532184&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/8791897572cb4507a6d625712860c911&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (B)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/a6ad16fd54df4743a70456583d91252a&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/33aa8991f5c147a28ed915c577f2a843&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (Ug)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/98782327bdd7429d88953b25803f87a6&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/79917bc2d6b04a8db066f0c0b54a88f4&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (R)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/fa41907066304c85bf1a08987da9ffcc&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (Ub)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/af5791dd4de740feb4cd698aa3bca308&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/c1b4d4eeba174359b0cd107d387aad53&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/4b27bc3e10d944dfa114266fb26332f9&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (B)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/46e25e837f1e40aeb18e5e080ad589d1&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/369b816e47cd4f97808303ece84a40ae&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/b5543dd9f934473285a5b0eb69b311ef&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/f04e00a27de64eb78c99f9f6ec21d2c5&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (RG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/edf1117549a24a10b313d9b37d0e4123&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UB)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/8c31ec527ba649e0a6d4240da11de2ac&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/bbfc12ee8fab4b54bbe3b21938cdb7ab&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (WR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/ad9a2586c74a4a919b89bab10885c8bc&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UW)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/e665c3156cb94a369e3dee617970cd5c&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/acc581650cc5420fb3c99549cc1b0d25&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (U)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/d1fc649ae57642fcad9305ff02f5a6f0&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/d309bafcf0384a2f8c375e385388b028&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (RG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/148c478939114ddab430662504bd8c2d&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UB)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/a22997624be1489287ab07264fdf64f3&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/d69ec42f8d2c4198ad39fceb7af758fe&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/441247cb023f453781b7d0166b0e5460&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (UB)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/8908a1c02fc24542be34c60c4bfc2ec8&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P +WRG -B (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/d8262b6f9f5a4623a8e4e8c23b0d3469&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/cc1fafec3f364cfba11d4fac86de9996&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/d1c0524e0fbf4e73a7d7a8b0dae6f2bb&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (RG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/e765df16eb3643e7aaddc3660cc1994d&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P +UR - B (UB)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/02197b8276674fa6bb798d4803e2c669&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/46abf6da575f4306a0229a642bf07994&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/c1cea33dfab24764aff7135bbf421db1&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UB)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/bc1e1ca7ccb442bb9c4ff66f72b90d31&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P +WRG -B (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/6c1e23e253ff4e70a0d9025e1e906bb2&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P +UR - B (UB)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/f298981f6ed240fab86548b3ee3e30a4&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P +WRG -B (G)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/dae6a7596d514cbcb06766fb49710936&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P +UR - B (RG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/9306775945d442fa88d8c73852b0709c&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UB)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/e9e347f88c774153995770b93fb1852e&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P +WRG -B (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/46f9076fc1d34ebb95cb7d5c46dc46e0&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P +UR - B (WR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/503e79087e24413fb26ace4f0dc67603&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P +WRG -B (WR)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;D&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/3ac8e865cebb4285b103306ef67dff81&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WB)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/f481619b773c484388c4cf64315779f7&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (UG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/b16c7fe72cef40e381bb0e0afe1ee365&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WB)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/1d5ae7dde9e9410db08351aa5bf7c0a3&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (R)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/33896b264346413c852c735824de85db&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (RG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/05e0eab645b04d549191dd810d91ecb9&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/2aa725a16caf4ccd8c4217232b925a17&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/aeaf071c48554d23925769e866135912&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (UB)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;D&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/44b785baa79841b586187ac5a4439a7f&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (WR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/cefba4b8d93b491f97b532d77317067a&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/7aa7c55ec1a94d49b5bc4500405c4820&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (Bw)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/3b91554f534e4409ad15a8dce2d298ec&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (R)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/8661246bce364df4968ced3da358ce97&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/f3794bbe6d68464da93a324f36775997&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (RG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/2dc713da1fd44c6194a1c09de974b9a6&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (Uw)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/a04205b4fd6e448da49f45368e93be2a&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UB)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;D&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/3f5ce3004d5740898cb184e1215361e1&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (WR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/9794c9af82f1420da3d31228b8b104dd&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/1542025525d6451bb0cc007706c43c8c&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (Wg)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/0b7121c11fd94daf96715a8ef7691057&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (R)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/5281779ca79a491f8f86ed176f63754c&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (BG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/8d36dfc289ae476da8d43153d827b657&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UB)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/e8d8397a550c4429b0a8c279eab5acd4&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/dd5b6370d8304f2dab035ee876fbafe9&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (U)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;D&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/1857aea052204604aa9baccf41d2f6b9&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P +WRG -B (WU)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/51144eec884041d4b743147e513b7cb3&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/9a65318087e04dd3a7467e4ccb7c7a0e&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/6c4961944596417890df8ea95c4decf7&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (Rb)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/3214f45828ab417e884929ba0a8a53f1&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P +UR - B (RG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/b3f9c08321494187a5edc384801d3681&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UB)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/cfaa3f6629ad45bcb797da415417ab02&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;E (WG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/2c5d28de1cf845baac46f775574aee66&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (UB)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;D&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/8e8d05f3641148e4a24f2c93e7c45197&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P +WRG -B (W)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/2747761d50c148268d9d90f6562a02d6&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P +UR - B (UB)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/2400c753a95640db9324557df9ea07d1&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P +WRG -B (R)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/d39f9281af36427a9dc8839efe2556c3&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P +UR - B (Gw)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/135bc2c9c8424942a342343b0206b7db&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;H (BG)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/1e9f9dfdb7984ecb8a5fa7bc1ea3105a&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P +WRG -B (UR)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/e320f33e6c544b698e55797341b15c4f&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P +UR - B (UW)&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;https://blog.17lands.com/draft/56821191698c411ea47110fb1a17c455&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;P +WRG -B (UB)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;While our draft bots don’t mimic human behavior perfectly, this sort of simulation serves as a great learning tool for the effects of these different styles. You’ll see plenty of cases where the preference bots get pushed out of the colors they want, and cases where the easy-way drafters end up in the same lane as if they drafted the hard way. Overall, though, these bots help illustrate some of the nuance that the top limited minds recommend.&lt;/p&gt;
&lt;p&gt;Easy-way drafters will see a lot more volatility in their results. In some cases, &lt;a href=&quot;https://www.17lands.com/draft/be9cfe570cad490c89f0b4fc03c21f79&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;like this one&lt;/a&gt;, you wind up with the nuts aggressive WR deck where your biggest challenge is figuring out all the cuts. In other cases, though, you’ll find yourself one of multiple UB drafters and wind up scrapping for playables. Hard-way drafters may need to bob and weave a bit before settling into the right lane, but &lt;a href=&quot;https://www.17lands.com/draft/33550335713c40bd9efbd8b077de4da3&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;they can be very rewarded&lt;/a&gt; for doing so in many cases. In other cases, drafting the hard way can wind up &lt;a href=&quot;https://www.17lands.com/draft/ad9a2586c74a4a919b89bab10885c8bc&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;postponing the decision too far&lt;/a&gt; leaving you unsure what colors you are in or reading signals incorrectly just because the packs fall a certain way. Drafting with preferences will usually leave you with a good second pack if you’re able to force your neighbor to the right out of your colors, but you can also be filling your deck with a bit of chaff in pack three if &lt;a href=&quot;https://www.17lands.com/draft/503e79087e24413fb26ace4f0dc67603&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;the person passing to you is in your same colors&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It won’t be universally true, but in a pod full of easy-way drafters (perhaps your local FNM), drafting the hard way will usually yield the best results. In a pod of hard-way drafters (maybe your next MTGO draft), pushing your way into the best colors with preferences will wind up with a good deck. Put in too many preference drafters, though, and drafting the hard way will often take back the crown. The small sample of data we’ve provided here can’t show this outright, but it’s another step along the path to demonstrating these ideas and also perhaps better showing where they might not hold. Our next goal with these simulations will be to recommend a deck build from each drafted pool and estimate the strength of that resulting deck. If we’re able to build a good version of that, you can be sure we’ll run a much larger set of simulations and share the results.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Do you want to help contribute data for analyses like these in the future? Check out our &lt;a href=&quot;https://www.17lands.com/getting_started&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Getting Started&lt;/a&gt; page to install the lightweight Arena tracker and get access to all of our deck, draft, and gameplay tracking!&lt;/p&gt; ]]></description>
    <pubDate>Sat, 25 Apr 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>Stark Reality - Drafting the Hard Way</title>
    <link>https://garden.linusboyle.cn/source/clipped/Stark-Reality---Drafting-the-Hard-Way</link>
    <guid>https://garden.linusboyle.cn/source/clipped/Stark-Reality---Drafting-the-Hard-Way</guid>
    <description><![CDATA[ &lt;p&gt;&lt;img src=&quot;https://mktg-assets.tcgplayer.com/fit-in/1300x1300/filters:quality(75)/content/opengraph/MTG-Mist-Raven-AVR.jpg&quot; alt=&quot;Stark Reality - Drafting the Hard Way&quot; loading=&quot;lazy&quot;&gt;&lt;/p&gt;
&lt;p&gt;TCGplayer Series:&lt;/p&gt;
&lt;p&gt;A lot of people ask me for help with booster drafting. I wish so badly it were the kind of thing where I could take 20 minutes of my time to listen to how they draft, tell them what they are doing wrong, and how to fix it. It just isn’t. Booster drafting well is incredibly complex.&lt;/p&gt;
&lt;p&gt;The best way I can describe it is that there are two ways: The easy way and the hard way. If you draft the easy way all the time, you can spike when things line up your way and you are perfectly live to 3-0 and draft good decks when they do, but around half the time you will not end up with a good deck at all and will be liable to 0-3 or 1-2 your draft. If you draft the hard way you can have a good deck in 90 percent of your drafts. Sound great? What’s the problem? Well, the hard way is hard.&lt;/p&gt;
&lt;p&gt;Drafting the hard way means analyzing each new format and being willing to forget about whether you like control or beat down, white or black. Forgetting about what was working for you in the last format and starting to evaluate everything from scratch all over again. Always being willing to drop early picks if you realize something else is open. It means not sticking to the strategy or strategies that you think are best but weighting the cards that are important for those correctly, and then still being willing to draft completely different decks if that’s what is open.&lt;/p&gt;
&lt;p&gt;It requires allowing your decks to go different directions in each draft and not predetermining where you are going to go. Every draft format is different and every draft is different. I don’t even like doing our house practice drafts, because they bias me into thinking you should go certain directions more than you should, because certain strategies are either open or would work well against what the others in the group are doing. I generally prefer these days to watch the draft so that I don’t get as caught up in trying to win. Instead I spend more time watching how the commons interact with each other and trying to pick up on how the games and format plays out.&lt;/p&gt;
&lt;p&gt;Different things are a little more or a little less important in each new format. So at the start of a new format, I’m mostly trying to identify whether flying is a little better (&lt;em&gt;Return to Ravnica&lt;/em&gt;). How about lifelink? (&lt;em&gt;Zendikar&lt;/em&gt;). Is this a format where drawing cards is a little bit more profitable than usual (&lt;em&gt;Modern Masters&lt;/em&gt;)? Or is this a format where a lower mana cost is of extra value (&lt;em&gt;Gatecrash&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;Let’s look at a good example of this. I remember when we started our testing for PT Avacyn Restored, most people thought Seraph of Dawn was better than Mist Raven. It’s not hard to see how this happened. In an aggressive format, the 2/4 would be much better, and in a format where the cheap cards were more powerful, the 2/4 would also be much better. &lt;em&gt;Avacyn Restored&lt;/em&gt; was neither of those things, but the format directly before, &lt;em&gt;Innistrad&lt;/em&gt; - &lt;em&gt;Dark Ascension&lt;/em&gt;, was both.&lt;/p&gt;
&lt;p&gt;It was a format where the cheap cards like Werewolves and Travel Preparations hit hard and prevented late games, or were still good in the late game. In that format, the 2/4 would have been better than Mist Raven. In &lt;em&gt;Avacyn&lt;/em&gt;, however, the cheap cards were horrible. Games were mostly decided by individual powerful cards. The tempo swing from being able to bounce a soulbond that was preventing you from attacking or bouncing their powerful five-plus mana card that they were depending on to swing the game was extremely valuable. The two life a turn that makes it almost impossible to race the 2/4 was not particularly amazing, since you weren’t usually racing. The 2/4 is still a good card, and one that could help you win games, but it was not the bomb it would have been in formats like &lt;em&gt;Innistrad&lt;/em&gt; - &lt;em&gt;Dark Ascension&lt;/em&gt;, &lt;em&gt;Zendikar&lt;/em&gt; or &lt;em&gt;Gatecrash&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The single thing people do that ruins most drafts is stick to their early picks. In the vast majority of draft formats, you should be trying to figure out what is underdrafted at the table so that you can have access to a lot of what you are looking for in packs two and three. Also, by identifying which colors or archetypes the people to your right aren’t playing, you end up having several packs to get incredibly powerful picks from. If you stick to your first picks, you often end up with few packs to select first-pick quality cards from.&lt;/p&gt;
&lt;p&gt;People often think that they can just jam what they want, because if they are cutting something off then they will have access to the cards that they want in pack two even if not in pack three. This only works when pack two is specifically more valuable than pack three. Even if you draft mono-white from pick one, there were probably a few other white cards in the packs, and if the guy to your left or to his left is drafting in easy mode (95 percent of people are) and he opened or got passed a white card from the person passing to him (if it’s the guy two seats down), then they are probably still going to draft white despite you not passing them any great cards in that color.&lt;/p&gt;
&lt;p&gt;On the other hand, if you get a first-pick quality white card pick four, and a second to fourth pick quality blue card pick eight, while nothing is guaranteed, you can bet your ass the vast majority of the time that the people to your right aren’t drafting white and blue is heavily underdrafted at the table. The exception to this rule are formats where pack two is of disproportionately greater importance to you than pack three.&lt;/p&gt;
&lt;p&gt;A perfect example of this is DGR if you start out in a &lt;em&gt;Gatecrash&lt;/em&gt; guild. Since you don’t care much about pack three, and pack two is your entire world, if your first two picks put you into a specific &lt;em&gt;Gatecrash&lt;/em&gt; guild, you can just jam that guild and not bother to read what the people passing to you are playing, or what is being underdrafted in the pod, since you basically live and die by only pack two, and you are only looking for strong cards out of the first few picks of pack two. Draft formats where this is correct like DGR are few and far between though.&lt;/p&gt;
&lt;p&gt;The next thing that often ruins drafts is trying to draft the nuts or the best deck. Going for a combo or cards without synergy that don’t fit their deck’s plan, or are difficult to cast but have a high power level. I have 3-0’d so many draft pods with very mediocre looking decks. You don’t need to be in the best color or archetype, you don’t need a way to win, you don’t even need particularly powerful cards to win. If your deck is fully functional, meaning the cards you do have work together, your curve is good for the format, and your mana allows you to cast your spells when you need to cast them (some formats you are under more pressure (&lt;em&gt;Gatecrash&lt;/em&gt;), some you have a little more time (&lt;em&gt;Rise of Eldrazi&lt;/em&gt;), that is good enough to allow you to 3-0 any pod. Sure you won’t have the best deck in the pod, but that’s not how Magic works.&lt;/p&gt;
&lt;p&gt;The most common scenario is not that you have the third best deck, and you play against the best or second best deck you lose, otherwise you win. In that case, drafting the second or third best deck in the pod every time would result in 2-1 every time. In reality, when you have the third best deck and you play against the best deck in the pod, you are usually just a small underdog because your deck is very good anyways. In general I feel outmatched when I play my 2-0 match in my draft pods, but assuming roughly even play skill I win that match around 45 percent of the time, because I have a good, fully functional deck. If he stumbles, gets flooded, or my cards just happen to line up well against his, I can very easily win. When you have good, fully functional draft decks, it is very easy to beat a better deck. When you have trainwrecks/bad draft decks it is very difficult to beat anyone.&lt;/p&gt;
&lt;p&gt;A good example of this approach would be my first draft in PT Gatecrash. It was covered in the draft viewer so you can go back and check it out. I started out with some Orzhov stuff (the guild I consider the best by miles in triple-Gatecrash), but I wasn’t seeing Orzhov, so around pick five, pack one, I realized Simic was open and completely jumped ship. I was very fortunate to have this opportunity. I had it because a lot of the other players in the draft were unwilling to draft Simic, because they thought it was the worst of the five guilds (personally I think it was the fourth of the five guilds and not particularly good, but that Dimir was the worst). This imbalance allowed good Simic cards to come late, telling me that Simic was wide open and I jumped ship, drafted a mediocre Simic deck, and went 2-1.&lt;/p&gt;
&lt;p&gt;If I had stuck to Orzhov, my deck would have been absolutely terrible, and while I have no idea what my record would have been, my EV in wins in the draft would have been much lower. I obviously was very unhappy to have to move from the best guild in the format to the fourth best guild out of five, but you don’t want to dictate what you draft, you want to draft what you see and what is being underrated. Any fully functional, reasonable draft deck, can 2-1 or 3-0 a pod. Trainwrecks struggle to get a win.&lt;/p&gt;
&lt;p&gt;It took many years of endless drafting for me to improve my draft game and I’ve spent many years trying to slowly improve the drafting skill of many of my closest friends. If you are willing to play the game in hard mode, don’t expect to be good at it quickly or to immediately start crushing. However, if you are willing to read every draft, be open to drafting whatever archetype is available that draft, and even drop bomb-rare first picks, you can put together a good draft deck in almost every draft you do and you can be a highly successful booster drafter. Will you accept this challenge? The choice is yours.&lt;/p&gt; ]]></description>
    <pubDate>Sat, 25 Apr 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>SOS轮抓手记</title>
    <link>https://garden.linusboyle.cn/idea/20260424093358-SOS%E8%BD%AE%E6%8A%93%E6%89%8B%E8%AE%B0</link>
    <guid>https://garden.linusboyle.cn/idea/20260424093358-SOS%E8%BD%AE%E6%8A%93%E6%89%8B%E8%AE%B0</guid>
    <description><![CDATA[ &lt;h2 id=&quot;总览&quot;&gt;总览&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#总览&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;整体趋势是多色控制/5c聚辉 v.s. 快攻；聚辉更强，也更容易抓，调色很重要；快攻组件不齐难成形&lt;/p&gt;
&lt;h3 id=&quot;多色控制聚辉&quot;&gt;多色控制/聚辉&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#多色控制聚辉&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;以大法术和回收坟场作为终端，主2~3色，通过珍宝/调色手段混色以及激活聚辉&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ramp/调色：加速神器，红石板，找地载具，两组双色地&lt;/li&gt;
&lt;li&gt;聚辉payoff：协力如一，聚辉放逐人，4B弃牌，5G造两token&lt;/li&gt;
&lt;li&gt;磨牌库制胜：U磨牌人，XXUU指数抓牌（12费稳定获胜）&lt;/li&gt;
&lt;li&gt;红蓝底：可以不混色，单纯走红蓝大法术流
&lt;ul&gt;
&lt;li&gt;调色：Sanar，222珍宝哥布林，抓二弃一造珍宝，213调色人&lt;/li&gt;
&lt;li&gt;大法术力payoff：XXU小回收，4UUU大回收，XUR爆头，1UURR扫4或者抓4，3UR打5，5UR造两鸟/前期润滑&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;蓝绿底：几乎必然要混色，补足去除
&lt;ul&gt;
&lt;li&gt;调色：111熊，222找地人，4费回手ramp，死触蛙&gt;递增人&lt;/li&gt;
&lt;li&gt;大法术力payoff：2UG复制+6豆，XUG分形鸟，XG分形刺探，Jadzi&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;法术循环组件：蓝色大小回收，绿尊贤，644，322先攻&lt;/li&gt;
&lt;li&gt;混色对象：2WR约柜，3WWBB，黑、白、绿杀和扫&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;combo&quot;&gt;Combo&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#combo&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;322先攻+2UG复制能达成每回合造66先攻；当回合使用一次比较保险，需要7费4色&lt;/li&gt;
&lt;li&gt;黑绿锅+444能无限造11虫和挖坟&lt;/li&gt;
&lt;li&gt;2WR打5从坟场或放逐区施放时只需要2费，可以配合约柜、322先攻、石板等
&lt;ul&gt;
&lt;li&gt;同理，1WW脱缰古物此时有加豆效果&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;任何需要输注的法术都可以先施放，再响应启动加速神器加血&lt;/li&gt;
&lt;li&gt;3WWBB和644可以循环&lt;/li&gt;
&lt;li&gt;2B捡坟+644&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;underrated&quot;&gt;Underrated&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#underrated&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;3WWBB: Moment of Reckoning&lt;/li&gt;
&lt;li&gt;聚辉放逐人：Sundering Archaic&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;overrated&quot;&gt;Overrated&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#overrated&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;除红之外的定式，尤其是黑定式&lt;/li&gt;
&lt;li&gt;211云移人，323偷咒语人&lt;/li&gt;
&lt;li&gt;拉尔（黑白可用）&lt;/li&gt;
&lt;li&gt;10费古旅人，基本只在红蓝底控制有效&lt;/li&gt;
&lt;li&gt;黑绿龙&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;记录&quot;&gt;记录&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#记录&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;0425-第一抓-单抓-1-3&quot;&gt;0425 第一抓 单抓 1-3&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#0425-第一抓-单抓-1-3&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;红白，第二包换色到红蓝，整体是个偏控制的法术瞬间套组&lt;/p&gt;
&lt;p&gt;失误是&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;放过了很多红白的法术（比如Molten Note）、生物和地，本来可以是一般的红白套组，或者洁斯凯；&lt;/li&gt;
&lt;li&gt;没有wincon。第二包有的Sundering Archaic也可以算制胜（洗回牌库）和法术力水槽，没有意识到&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我感觉多色套组会在后续表现更好。从这一抓来看，如果是红白或是黑白快攻都需要不少组件，抓的人基本只在这个体系下有用。有些牌在快攻之外也可以用，比如红白的4费解，前期抓了后面多色控制套组也可以用。所以可能更好的策略是尽量保持开放，留出打多色的可能？&lt;/p&gt;
&lt;p&gt;群里老哥的复盘：对牌的强度不敏感，第一包传了很多好牌下去，信号会乱；force红白会更好，至少是一套能玩的红白；第二包抓的很有问题，放了太多牌&lt;/p&gt;
&lt;h3 id=&quot;0426-第一抓-单抓-3-3&quot;&gt;0426 第一抓 单抓 3-3&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#0426-第一抓-单抓-3-3&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;苏勒台，有一堆黑去除和扫，蓝绿底不够，少ramp，蓝牌的作用很少； 制胜纯靠绿结界&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;大法术瞬间不够，U磨牌库人基本没用；适合有大量大费牌的控制&lt;/li&gt;
&lt;li&gt;黑绿是比较开放的，在抓蓝牌的时候有几张黑绿牌可以抓，可能最后组出来的黑绿强度更高一点&lt;/li&gt;
&lt;li&gt;P1P1直接抓熊不太对，应该是黑绿锅的&lt;/li&gt;
&lt;li&gt;P1P3过高位抓调色神器，不过它可以配合输注牌瞬间回血（相应输注启动异能），但是注意在17lands数据显示纯黑绿有它胜率暴跌，可能更适合作为插件。
&lt;ul&gt;
&lt;li&gt;这一抓112或者互斗比较好&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;复盘会发现第一包黑白是开放的（Snooping Page是信号），然后第二包直接P1抓金，后面的所有黑白牌都回传了&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;0426-第二抓-双抓-3-2&quot;&gt;0426 第二抓 双抓 3-2&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#0426-第二抓-双抓-3-2&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;带炸弹神器的红白，有不少造22的人，但是没有314&lt;/p&gt;
&lt;p&gt;双抓模式下因为开的包只有原来的一半，即使没撞色，有些关键的牌很有可能就是开不出来，所以虽然套牌整体更一致，但是强度不一定就更高。比起单抓，信号更好识别，但是读信号会更重要，force色组更难。&lt;/p&gt;
&lt;h3 id=&quot;0426-第三抓-双抓-4-0&quot;&gt;0426 第三抓 双抓 4-0&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#0426-第三抓-双抓-4-0&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;抓的不如上一次，但是卷了。双抓的对手强度似乎要低一点&lt;/p&gt;
&lt;h3 id=&quot;0426-第四抓-双抓-4-0&quot;&gt;0426 第四抓 双抓 4-0&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#0426-第四抓-双抓-4-0&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;蓝绿底的铁木尔，核心是前期用死触蛙这种站住+加速，同时大量2跳4，用高费咒语碾压。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;抓的时候大概是在第四到第五pick发现信号&lt;/li&gt;
&lt;li&gt;444 Sloth很强&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;0429-第一抓-双抓-1-2&quot;&gt;0429 第一抓 双抓 1-2&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#0429-第一抓-双抓-1-2&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;铁木尔混黑，ramp太多，payoff太少，制胜竟只有磨牌人，绿结界和分形鸟&lt;/p&gt;
&lt;h3 id=&quot;0429-第二抓-双抓-1-2&quot;&gt;0429 第二抓 双抓 1-2&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#0429-第二抓-双抓-1-2&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;又是铁木尔，但是质量差得多&lt;/p&gt;
&lt;p&gt;红蓝现在绝对是抢的人很多，而没有红蓝混色payoff蓝绿基本上没什么强度。双抓情况下如果有撞色的情况就会像这样很糟。&lt;/p&gt;
&lt;h3 id=&quot;0430-第一抓-双抓-0-2&quot;&gt;0430 第一抓 双抓 0-2&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#0430-第一抓-双抓-0-2&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;没有配合的红白，有白黑炸弹，但没有调色只能卡手里&lt;/p&gt;
&lt;p&gt;卡组构建比较矛盾，因为没有红白配合牌，转向前期快攻，小人又不够，同时还有7费的终端，就很呆。&lt;/p&gt;
&lt;p&gt;但是另一方面，既没有高费终端，又没有大量低费曲线的中速真的是拉完了。&lt;/p&gt;
&lt;h3 id=&quot;0510-第一抓-快抓-5-3&quot;&gt;0510 第一抓 快抓 5-3&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#0510-第一抓-快抓-5-3&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;没有足够payoff，但是离坟挺多的红白，大多数时候是靠横向展开踢死的。&lt;/p&gt;
&lt;h2 id=&quot;low-prio-list&quot;&gt;Low-Prio List&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#low-prio-list&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Essence Scatter&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Sleight of Hand&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Render Speechless&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Quandrix Charm&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Burrog Banemaker&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Spellbook Seeker&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Tackle Artist&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Potioner’s Trove&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Hydro-Channeler&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Pterafractyl&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Deluge Virtuoso&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Textbook Tabulator&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Send in the Pest&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Rapier Wit&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Brush Off&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Colossus of the Blood Age&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Return the Favor&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Seize the Spoils&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Shopkeeper’s Bane&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Pest Mascot&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Spell Pierce&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Bulk Up&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Duel Tactics&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Mica, Reader of Ruins&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Stadium Tidalmage&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Elemental Mascot&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Spirit Mascot&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Rearing Embermare&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Strifle Scholar&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Tenured Concocter&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Hungry Graffalon&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Wild Hypothesis&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Visionary’s Dance&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Banishing Betrayal&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Blazing Firesinger&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Royal Treatment&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Efflorescence&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Masterful Flourish&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Pursue the Past&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Melancholic Poet&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Shattered Acolyte&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Tester of the Tangential&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; checked disabled&gt; Social Snub&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Procrastinate&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Muse’s Encouragement&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Embrace the Paradox&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Ancestral Anger&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Fractal Tender&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Pull from the Grave&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Rancorous Archaic&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Mage Tower Defense&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Owlin Historian&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Chelonian Tackle&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;related&quot;&gt;Related&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#related&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../idea/MTG&quot; class=&quot;internal&quot; data-slug=&quot;idea/MTG&quot;&gt;MTG&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt; ]]></description>
    <pubDate>Fri, 24 Apr 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>Do the Bots Send Signals?</title>
    <link>https://garden.linusboyle.cn/source/clipped/Do-the-Bots-Send-Signals</link>
    <guid>https://garden.linusboyle.cn/source/clipped/Do-the-Bots-Send-Signals</guid>
    <description><![CDATA[ &lt;p&gt;Draft is often cited as the biggest test of skills for a Magic player, as there are three distinct areas where a drafter must excel in order to do well: drafting, deckbuilding, and playing. With the advent of Arena, “the bots” have disrupted the drafting component significantly. In this post, we’ll try to explore how bots affect the way we draft, backed up by data from real Arena and Magic Online drafts.&lt;/p&gt;
&lt;h2 id=&quot;drafters-incentives&quot;&gt;Drafters’ Incentives&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#drafters-incentives&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Drafting with humans in seats next to each other is not a zero-sum game. Players must cooperate with the drafters next to them in order to end up with better decks. If they instead fight over cards of the same color, they’ll wind up with worse decks and lose more games. Because 5/7 games (on average) in an 8 person pod are played against opponents that aren’t your neighbors, there is an incentive to make your own deck better, even if it means your neighbors’ decks are a little better too.&lt;/p&gt;
&lt;p&gt;The introduction of leagues in Magic Online altered these incentives slightly. When drafting and playing in-pod, “hate drafting” has some benefit if you can make your neighbor’s deck worse at little to no cost to your own deck. In leagues, however, drafters play against opponents outside of their pod, and hate drafting has almost no effect, since the chance of playing against your neighbor is very small.&lt;/p&gt;
&lt;p&gt;In Arena, humans draft against seven automated draft bots. Because the bots only take cards out of packs and don’t have to build decks or play matches, the drafting experience is significantly altered. By not playing matches, the bots don’t have any incentive to send or receive signals outside of WotC trying to keep Arena interesting to limited players. With that in mind, let’s try to evaluate how far off from a real drafting experience drafting on Arena is.&lt;/p&gt;
&lt;h2 id=&quot;establishing-card-ratings&quot;&gt;Establishing Card Ratings&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#establishing-card-ratings&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Because players aren’t allowed to communicate during a draft, the only way for a player to know what colors their opponent is drafting is to infer that information from the cards being passed. The simplest solution might be to count the number of cards in each color, but there’s a lot of variance in that. Instead, we get better signal from the card strength. If the blue, white, and red cards being passed to a player in the first pack are consistently stronger than the green and black ones, it’s more likely that the person to their right is drafting green and black. But what do we mean by “stronger”?&lt;/p&gt;
&lt;p&gt;To evaluate strength, we need to understand how our neighbors value the cards. This is challenging to do unless we have lots of data to work with. With hundreds of drafts, we can identify the rating of cards based on how late we see each card in a pack on average. To illustrate with an example, let’s look at&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=461061&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Invading Manticore&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;in &lt;a href=&quot;https://www.17lands.com/draft/e688e13849bf46bf9e3a7f07f8fa1242&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;this draft&lt;/a&gt;. Throughout the draft, we see it the following times:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pack 1 pick 1&lt;/li&gt;
&lt;li&gt;Pack 1 pick 9 (indicating no one took this picks 2 through 8)&lt;/li&gt;
&lt;li&gt;Pack 3 pick 7&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For any card that wheels (i.e. we see it again when the pack comes back around), we ignore the first time we saw it. Using just the data from the draft above, the “average available position” for&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=461061&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Invading Manticore&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;would be 8.0. Averaging across all the WAR drafts shared using 17Lands, the actual number for&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=461061&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Invading Manticore&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;with the Arena bots is 7.6. We also have data from hundreds of Magic Online drafts with human drafters to compare to, provided by &lt;a href=&quot;https://magicprotools.com/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Magic Pro Tools&lt;/a&gt;. Averaging across those human drafters, that number for&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=461061&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Invading Manticore&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;is 6.2. A great card like&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=497670&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Spark Harvest&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;is usually only available in the first couple of picks, and its number is 3.0.&lt;/p&gt;
&lt;p&gt;To turn this “average available position” into a number representing the strength of the cards being passed, we scale this number to be between 0 (lowest valued) and 1 (highest valued), and then square it to account for good cards being significantly more valuable than mediocre cards. The table below shows this value for a sample of &lt;em&gt;War of the Spark&lt;/em&gt; cards for Arena drafts logged on 17Lands between May 9 (the most recent announced update to the bots) and June 20 and from the sample of MTGO drafts uploaded to Magic Pro Tools.&lt;/p&gt;





























































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;Rarity&lt;/th&gt;&lt;th&gt;Colors&lt;/th&gt;&lt;th&gt;Humans Value&lt;/th&gt;&lt;th&gt;Bots Value&lt;/th&gt;&lt;th&gt;Difference&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Arlinn’s Wolf&lt;/td&gt;&lt;td&gt;common&lt;/td&gt;&lt;td&gt;G&lt;/td&gt;&lt;td&gt;0.31&lt;/td&gt;&lt;td&gt;0.497&lt;/td&gt;&lt;td&gt;0.187&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Arlinn, Voice of the Pack&lt;/td&gt;&lt;td&gt;uncommon&lt;/td&gt;&lt;td&gt;G&lt;/td&gt;&lt;td&gt;0.776&lt;/td&gt;&lt;td&gt;0.787&lt;/td&gt;&lt;td&gt;0.012&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Bond of Discipline&lt;/td&gt;&lt;td&gt;uncommon&lt;/td&gt;&lt;td&gt;W&lt;/td&gt;&lt;td&gt;0.166&lt;/td&gt;&lt;td&gt;0.318&lt;/td&gt;&lt;td&gt;0.153&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Emergence Zone&lt;/td&gt;&lt;td&gt;uncommon&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;0.022&lt;/td&gt;&lt;td&gt;0.018&lt;/td&gt;&lt;td&gt;-0.004&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Invading Manticore&lt;/td&gt;&lt;td&gt;common&lt;/td&gt;&lt;td&gt;R&lt;/td&gt;&lt;td&gt;0.177&lt;/td&gt;&lt;td&gt;0.074&lt;/td&gt;&lt;td&gt;-0.103&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Living Twister&lt;/td&gt;&lt;td&gt;rare&lt;/td&gt;&lt;td&gt;GR&lt;/td&gt;&lt;td&gt;0.552&lt;/td&gt;&lt;td&gt;0.786&lt;/td&gt;&lt;td&gt;0.233&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Merfolk Skydiver&lt;/td&gt;&lt;td&gt;uncommon&lt;/td&gt;&lt;td&gt;GU&lt;/td&gt;&lt;td&gt;0.518&lt;/td&gt;&lt;td&gt;0.757&lt;/td&gt;&lt;td&gt;0.239&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Mobilized District&lt;/td&gt;&lt;td&gt;rare&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;0.487&lt;/td&gt;&lt;td&gt;0.881&lt;/td&gt;&lt;td&gt;0.394&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Vraska, Swarm’s Eminence&lt;/td&gt;&lt;td&gt;uncommon&lt;/td&gt;&lt;td&gt;BG&lt;/td&gt;&lt;td&gt;0.828&lt;/td&gt;&lt;td&gt;0.846&lt;/td&gt;&lt;td&gt;0.018&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Wanderer’s Strike&lt;/td&gt;&lt;td&gt;common&lt;/td&gt;&lt;td&gt;W&lt;/td&gt;&lt;td&gt;0.474&lt;/td&gt;&lt;td&gt;0.567&lt;/td&gt;&lt;td&gt;0.092&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;finding-your-lane&quot;&gt;Finding Your Lane&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#finding-your-lane&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We can’t interpret the power level of colors in any one pack to be fully indicative of what our neighbor is drafting. However, if we track the power level throughout all of the picks in a pack, we get a pretty good sense of what those passing to us are drafting. Assuming the other drafters don’t change colors after the first pack, we expect to see the total power level passed to us in pack one to be relatively close to the power level passed to us by those same drafters in pack three.&lt;/p&gt;
&lt;p&gt;To evaluate the benefit to finding the open colors, we’ll need a methodical way for doing so. For each color, we take the sum of the maximum-valued card in each pack of that color (we’ll split the value of multicolor cards evenly across their colors). Let’s take blue in &lt;a href=&quot;https://magicprotools.com/draft/show?id=YToekpZPp1IRG81NMS4ZWbFcsmA&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;this draft&lt;/a&gt; as an example.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pick 1 isn’t passed to us, so we don’t value it.&lt;/li&gt;
&lt;li&gt;P1P2,
&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=461147&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Tamiyo, Collector of Tales&lt;/a&gt;
adds 0.36 (because it is two colors, we split&lt;/li&gt;
&lt;li&gt;P1P3,
&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=539360&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Eternal Skylord&lt;/a&gt;
adds 0.79, bringing our total to 1.14.&lt;/li&gt;
&lt;li&gt;P1P4,
&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=651837&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Thunder Drake&lt;/a&gt;
adds 0.52. Total is 1.66.&lt;/li&gt;
&lt;li&gt;P1P5,
&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=460998&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Tamiyo’s Epiphany&lt;/a&gt;
adds 0.49, putting the total at 2.15.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And so on through the end of the pack. The total for blue throughout pack one comes out to about 3.26. In pack three, following the same logic, the total is about 3.62.&lt;/p&gt;
&lt;p&gt;The chart below shows these values for all the WAR Magic Online drafts submitted to Magic Pro Tools. Each draft has five data points: one for each color. The x-axis represents the total power level throughout pack one, while the y-axis represents the total for that same color seen throughout pack three.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.17lands.com/assets/img/posts/2019-07-01-bot-signals/open-lane-mtgo.png&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.17lands.com/assets/img/posts/2019-07-01-bot-signals/open-lane-mtgo.png&quot; alt=&quot;Open Lane Benefit: MTGO&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The positive slope demonstrates what we intuited before: there is a definite benefit to identifying the open colors in a draft! If you consistently get passed good cards in a color in pack one, on average you’ll see much better cards in the third pack in that color. This isn’t guaranteed, though. Other drafters could switch colors, or the cards could just be weaker in pack three.&lt;/p&gt;
&lt;p&gt;Below is a similar plot using Arena drafts with the bots’ valuations.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.17lands.com/assets/img/posts/2019-07-01-bot-signals/open-lane-arena.png&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.17lands.com/assets/img/posts/2019-07-01-bot-signals/open-lane-arena.png&quot; alt=&quot;Open Lane Benefit: Arena&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We see a similar trend, indicating that the Arena bots mirror the behavior of real drafters. In this case, the slope is even steeper, indicating there may be &lt;strong&gt;more&lt;/strong&gt; value to reading signals drafting with the Arena bots than with humans! If the bots send signals like humans, though, why does drafting against the Arena bots feel different from drafting against humans?&lt;/p&gt;
&lt;h2 id=&quot;difference-in-pick-order&quot;&gt;Difference in Pick Order&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#difference-in-pick-order&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The most obvious difference in drafting with bots is that their pick order is different. When bots overvalue cards like&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=129568&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Giant Growth&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;, drafters don’t have a chance to take it where they feel it should be going, and as a result it’s almost never seen in draft play on Arena. It is hard to notice the absence of something, though, and it not being there in any one draft isn’t that odd. What sticks out like a sore thumb, though, is when cards go way later than they should. There have been some extreme examples in past sets, like&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=563198&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Gate Colossus&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=651908&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Sauroform Hybrid&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;in RNA. Since the latest update to the bots, the examples in WAR aren’t quite so bad, but&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=460986&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Lazotep Plating&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=643082&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Dreadmalkin&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;are a couple that still seem to stick out.&lt;/p&gt;
&lt;h2 id=&quot;pick-order-variance&quot;&gt;Pick Order Variance&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#pick-order-variance&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Another key insight is that the bots are much stricter with their pick order than the variety of humans who draft. Looking at the variance of how late cards are seen across the pick order, this becomes clear:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.17lands.com/assets/img/posts/2019-07-01-bot-signals/pick-position-variance.png&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.17lands.com/assets/img/posts/2019-07-01-bot-signals/pick-position-variance.png&quot; alt=&quot;Pick Position Variance&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The first thing to note from this graph is that there are quite a few cards with zero variance - there are 18 rares and mythics that the Arena bots have never passed in the hundreds of drafts recorded, even in the third pack when it’s not in their colors. This compares to only four cards never passed in the sample of Magic Online drafts. There are three reasons someone might take a card that they’re not going to play: they can sell it, they need it outside of the draft, or they’re hate drafting. Because there’s no secondary market on Arena, the first reason wouldn’t apply, so we would expect less of this behavior, not more.&lt;/p&gt;
&lt;p&gt;The other thing to note from this graph is that across the entire pick order, the variance is lower. This indicates that the bots likely have a very strict pick order within each color, and they stick to it throughout the draft. Not only do different human drafters have different valuations of the cards, but even an individual drafter’s pick order will change throughout the draft to fill in holes in their deck. For example, someone might be light on two-drops and take&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=651904&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Kronch Wrangler&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;over&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=461081&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Bloom Hulk&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;later in the draft, even though the latter is a better card in a vacuum. Given the data presented, though, it’s unlikely the bots make these sorts of in-draft adjustments.&lt;/p&gt;
&lt;h2 id=&quot;self-correction&quot;&gt;Self-Correction&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#self-correction&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The metagame for drafting with humans is usually self-correcting. When blue and red are seen as the deepest colors in a format, more people draft those colors. As a consequence, they get fewer powerful blue and red cards, and the people who are drafting white, black, and green will get their choice of the powerful cards in the shallower colors. With the Arena bots being so strict in their pick order, though, the metagame doesn’t shift, and any mistakes in the bots’ card evaluation continue to be exploited. The table below shows the percentage of decks playing each color for 17Lands users’ opponents and the win rate of those decks (note that 17Lands players are better than average, thus their opponents’ have a win rate of under 50%):&lt;/p&gt;









































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Color&lt;/th&gt;&lt;th&gt;# Games&lt;/th&gt;&lt;th&gt;Metagame Share&lt;/th&gt;&lt;th&gt;Win Percentage&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;White&lt;/td&gt;&lt;td&gt;1063&lt;/td&gt;&lt;td&gt;35.1%&lt;/td&gt;&lt;td&gt;41.9%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Blue&lt;/td&gt;&lt;td&gt;1490&lt;/td&gt;&lt;td&gt;49.1%&lt;/td&gt;&lt;td&gt;44.4%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Black&lt;/td&gt;&lt;td&gt;1440&lt;/td&gt;&lt;td&gt;47.5%&lt;/td&gt;&lt;td&gt;43.8%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Red&lt;/td&gt;&lt;td&gt;1222&lt;/td&gt;&lt;td&gt;40.3%&lt;/td&gt;&lt;td&gt;43.7%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Green&lt;/td&gt;&lt;td&gt;1273&lt;/td&gt;&lt;td&gt;42.0%&lt;/td&gt;&lt;td&gt;43.1%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Even though white has a very low share of the metagame at around 35%, it still has the lowest win rate. We can see why when looking at another statistic: the power level of Arena packs when using the average human pick order derived from MTGO drafts:&lt;/p&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Color&lt;/th&gt;&lt;th&gt;Average Bot Value&lt;/th&gt;&lt;th&gt;Average Human Value&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;White&lt;/td&gt;&lt;td&gt;2.15&lt;/td&gt;&lt;td&gt;1.69&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Blue&lt;/td&gt;&lt;td&gt;2.47&lt;/td&gt;&lt;td&gt;2.15&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Black&lt;/td&gt;&lt;td&gt;2.22&lt;/td&gt;&lt;td&gt;1.88&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Red&lt;/td&gt;&lt;td&gt;2.16&lt;/td&gt;&lt;td&gt;1.83&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Green&lt;/td&gt;&lt;td&gt;2.35&lt;/td&gt;&lt;td&gt;2.06&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;In forming this data, we use the same methodology for finding the open colors earlier to value each pack, but then average across all packs from all Arena drafts logged. We compare the value using both the bot pick order and the human pick order. While white, black, and red are relatively close in the value the bots perceive they are passing, humans perceive white to be much worse on average. From humans’ perspective, blue is often the strongest. As a result, it’s generally better to move into blue, even if the bots are making it seem slightly less open.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#summary&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There’s a lot we can learn about how to best draft in Arena by looking at data. For the &lt;em&gt;War of the Spark&lt;/em&gt; bots, at least, it seems they do send signals worth reading, but it’s best to keep in mind that the signals are relative to the bots’ pick orders, not your own.&lt;/p&gt;
&lt;hr&gt;
&lt;hr&gt;
&lt;p&gt;Do you want to help contribute data for analyses like these in the future? Check out our &lt;a href=&quot;https://www.17lands.com/getting_started&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Getting Started&lt;/a&gt; page to install the lightweight Arena tracker and get access to all of our deck, draft, and gameplay tracking!&lt;/p&gt; ]]></description>
    <pubDate>Fri, 24 Apr 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>Learning from the Best</title>
    <link>https://garden.linusboyle.cn/source/clipped/Learning-from-the-Best</link>
    <guid>https://garden.linusboyle.cn/source/clipped/Learning-from-the-Best</guid>
    <description><![CDATA[ &lt;p&gt;How do the best play? There have been thousands of articles in Magic across the decades talking about this in some form or fashion, but through the magic of 17Lands we get the pleasure of looking at some aspects of this through a pure factual lens.&lt;/p&gt;
&lt;p&gt;We constantly hear people talking about “well that card has a higher win rate, but I see XYZ streamer doesn’t like that card” or “that card has a terrible win rate yet XYZ streamer plays it all the time”. For a while, we’ve wanted to provide a segmented view into the data to help dig into some of this, and today we’re announcing the release of a new cut of data to do just that!&lt;/p&gt;
&lt;p&gt;At a high level, we’ve broken down some users into different groupings based on their performance over the last few sets and computed many of our common statistics for each of those groups. You’ll be able to see these cuts of the data as dropdowns on pages you’re familiar with, like the &lt;a href=&quot;https://www.17lands.com/card_data&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Card Performance&lt;/a&gt; and &lt;a href=&quot;https://www.17lands.com/deck_color_data&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Color Performance&lt;/a&gt; pages, and you can get more detail on the methodology on the &lt;a href=&quot;https://www.17lands.com/metrics_definitions&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Metrics Definitions&lt;/a&gt; page.&lt;/p&gt;
&lt;p&gt;As an example, we can segment data by just top players and compare it to our overall user base. With this, we can see how aggregated data might be hiding the true top-end of a card, as it removes players who are more likely to play the card in situations where they aren’t maximizing its full potential.&lt;/p&gt;
&lt;p&gt;Below are some of our key takeaways from this cut of the data.&lt;/p&gt;
&lt;h2 id=&quot;top-players-play-checks-notes-the-best-cards-more-often&quot;&gt;Top players play checks notes the best cards more often&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#top-players-play-checks-notes-the-best-cards-more-often&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Shock! Awe! These are the top ten commons and uncommons that top players played more frequently than the average player. “Play Rate” means the # of copies of this per deck, on average, for that group. You can sort of think of it like the fraction of decks that include that card, though it’s also bumped up by decks playing multiple copies.&lt;/p&gt;







































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Card&lt;/th&gt;&lt;th&gt;Play Rate (All)&lt;/th&gt;&lt;th&gt;Play Rate (Top)&lt;/th&gt;&lt;th&gt;Δ Play Rate (Top-All)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555259&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Run Out of Town&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.279&lt;/td&gt;&lt;td&gt;0.438&lt;/td&gt;&lt;td&gt;0.158&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555250&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Make Disappear&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.233&lt;/td&gt;&lt;td&gt;0.357&lt;/td&gt;&lt;td&gt;0.124&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555227&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Raffine’s Informant&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.459&lt;/td&gt;&lt;td&gt;0.579&lt;/td&gt;&lt;td&gt;0.120&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555249&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Majestic Metamorphosis&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.301&lt;/td&gt;&lt;td&gt;0.411&lt;/td&gt;&lt;td&gt;0.109&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555281&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Girder Goons&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.371&lt;/td&gt;&lt;td&gt;0.474&lt;/td&gt;&lt;td&gt;0.102&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=591477&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Inspiring Overseer&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.446&lt;/td&gt;&lt;td&gt;0.520&lt;/td&gt;&lt;td&gt;0.073&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555244&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Expendable Lackey&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.302&lt;/td&gt;&lt;td&gt;0.374&lt;/td&gt;&lt;td&gt;0.072&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555449&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Brokers Hideout&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.397&lt;/td&gt;&lt;td&gt;0.464&lt;/td&gt;&lt;td&gt;0.067&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555203&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Backup Agent&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.370&lt;/td&gt;&lt;td&gt;0.437&lt;/td&gt;&lt;td&gt;0.067&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555214&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Gathering Throng&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.279&lt;/td&gt;&lt;td&gt;0.345&lt;/td&gt;&lt;td&gt;0.065&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Conversely, here are the top ten cards that top players put in their decks less often than the average player. Not exactly a “greatest hits” album:&lt;/p&gt;







































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Card&lt;/th&gt;&lt;th&gt;Play Rate (All)&lt;/th&gt;&lt;th&gt;Play Rate (Top)&lt;/th&gt;&lt;th&gt;Δ Play Rate (Top-All)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=416851&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Kill Shot&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.159&lt;/td&gt;&lt;td&gt;0.099&lt;/td&gt;&lt;td&gt;-0.059&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555288&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Midnight Assassin&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.115&lt;/td&gt;&lt;td&gt;0.058&lt;/td&gt;&lt;td&gt;-0.057&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555251&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Obscura Initiate&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.187&lt;/td&gt;&lt;td&gt;0.130&lt;/td&gt;&lt;td&gt;-0.056&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555321&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Riveteers Initiate&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.144&lt;/td&gt;&lt;td&gt;0.091&lt;/td&gt;&lt;td&gt;-0.053&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555208&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Celebrity Fencer&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.118&lt;/td&gt;&lt;td&gt;0.066&lt;/td&gt;&lt;td&gt;-0.051&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555267&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Witness Protection&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.112&lt;/td&gt;&lt;td&gt;0.065&lt;/td&gt;&lt;td&gt;-0.047&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555355&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Prizefight&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.190&lt;/td&gt;&lt;td&gt;0.145&lt;/td&gt;&lt;td&gt;-0.044&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555351&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;High-Rise Sawjack&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.124&lt;/td&gt;&lt;td&gt;0.081&lt;/td&gt;&lt;td&gt;-0.042&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=651845&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Deal Gone Bad&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.196&lt;/td&gt;&lt;td&gt;0.155&lt;/td&gt;&lt;td&gt;-0.041&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555350&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Glittermonger&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.099&lt;/td&gt;&lt;td&gt;0.058&lt;/td&gt;&lt;td&gt;-0.041&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;If you do a pure card quality analysis and say “how much win rate benefit did the top players gain purely from playing with higher card quality”, you come up with about +0.4% benefit to win rate. That’s not deck building, that’s not being better at playing the game, that’s literally just from putting better cards in their decks. Huge? No. But just another way the best players are creating an uneven playing field for themselves before the match even starts&lt;/p&gt;
&lt;h2 id=&quot;top-players-play-situational-cards-situationally&quot;&gt;Top players play situational cards… situationally&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#top-players-play-situational-cards-situationally&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;These are all cards that top players played at least 2 percentage points less often, but when they did, they got much better (relative) performance out of them than the average player.&lt;/p&gt;


















































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Card&lt;/th&gt;&lt;th&gt;Play Rate (All)&lt;/th&gt;&lt;th&gt;Play Rate (Top)&lt;/th&gt;&lt;th&gt;Δ Play Rate (Top-All)&lt;/th&gt;&lt;th&gt;Δ GIH WR (Top-All)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=590122&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Goldhound&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.128&lt;/td&gt;&lt;td&gt;0.092&lt;/td&gt;&lt;td&gt;-0.036&lt;/td&gt;&lt;td&gt;8.5 percentage points&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555351&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;High-Rise Sawjack&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.124&lt;/td&gt;&lt;td&gt;0.081&lt;/td&gt;&lt;td&gt;-0.042&lt;/td&gt;&lt;td&gt;7.1 pp&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555208&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Celebrity Fencer&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.118&lt;/td&gt;&lt;td&gt;0.066&lt;/td&gt;&lt;td&gt;-0.051&lt;/td&gt;&lt;td&gt;6.5 pp&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555332&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Witty Roastmaster&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.159&lt;/td&gt;&lt;td&gt;0.123&lt;/td&gt;&lt;td&gt;-0.035&lt;/td&gt;&lt;td&gt;6.2 pp&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555288&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Midnight Assassin&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.115&lt;/td&gt;&lt;td&gt;0.058&lt;/td&gt;&lt;td&gt;-0.057&lt;/td&gt;&lt;td&gt;6.2 pp&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555422&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Shattered Seraph&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.149&lt;/td&gt;&lt;td&gt;0.124&lt;/td&gt;&lt;td&gt;-0.025&lt;/td&gt;&lt;td&gt;6.1 pp&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555333&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Wrecking Crew&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.104&lt;/td&gt;&lt;td&gt;0.079&lt;/td&gt;&lt;td&gt;-0.024&lt;/td&gt;&lt;td&gt;5.8 pp&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=416851&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Kill Shot&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.159&lt;/td&gt;&lt;td&gt;0.099&lt;/td&gt;&lt;td&gt;-0.059&lt;/td&gt;&lt;td&gt;5.8 pp&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555355&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Prizefight&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.190&lt;/td&gt;&lt;td&gt;0.145&lt;/td&gt;&lt;td&gt;-0.044&lt;/td&gt;&lt;td&gt;5.7 pp&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555267&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Witness Protection&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.112&lt;/td&gt;&lt;td&gt;0.065&lt;/td&gt;&lt;td&gt;-0.047&lt;/td&gt;&lt;td&gt;5.7 pp&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Here are some thoughts on why they’re able to overperform with some of these situational cards:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=590122&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Goldhound&lt;/a&gt;
is an inherently weak card, but it does a lot of small things in synergy with treasures-matter, sacrifice-matters, pump spells to 2-1 with first strike/menace, and also fixes and ramps. None of those things individually makes it worth playing a 1/1, but the best players are finding the right spots where the payoff is “good enough”.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555208&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Celebrity Fencer&lt;/a&gt;
doesn’t do as much as other white 4 drops, but can be a fine finisher in a deck that stabilizes and has tons of token producers. The best players know to cut it from all but the most synergistic decks.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555351&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;High-Rise Sawjack&lt;/a&gt;
and
&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555333&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Wrecking Crew&lt;/a&gt;
are other examples of cards that more controlling decks with top end are probably fine playing, but you want to avoid most of the time.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555355&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Prizefight&lt;/a&gt;
can be extremely weak in decks without high toughness spells or treasure synergies.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Overall, every single card on this list is a card that works with some types of decks but needs to be cut from many others, and the best players are making the call to correctly cut the card more often.&lt;/p&gt;
&lt;h2 id=&quot;top-players-get-the-most-out-of-cards-that-generate-lots-of-decision-points-or-are-challenging-to-maximize&quot;&gt;Top players get the most out of cards that generate lots of decision points or are challenging to maximize&amp;#x3C;&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#top-players-get-the-most-out-of-cards-that-generate-lots-of-decision-points-or-are-challenging-to-maximize&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here is a list of the cards where top players got their biggest win rate advantage.&lt;/p&gt;


















































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Card&lt;/th&gt;&lt;th&gt;Play Rate (All)&lt;/th&gt;&lt;th&gt;Play Rate (Top)&lt;/th&gt;&lt;th&gt;Δ Play Rate (Top-All)&lt;/th&gt;&lt;th&gt;Δ GIH WR (Top-All)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=590122&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Goldhound&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.128&lt;/td&gt;&lt;td&gt;0.092&lt;/td&gt;&lt;td&gt;-0.036&lt;/td&gt;&lt;td&gt;8.5 pp&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=446130&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Tavern Swindler&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.016&lt;/td&gt;&lt;td&gt;0.013&lt;/td&gt;&lt;td&gt;-0.003&lt;/td&gt;&lt;td&gt;8.3 pp&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555328&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Torch Breath&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.080&lt;/td&gt;&lt;td&gt;0.062&lt;/td&gt;&lt;td&gt;-0.017&lt;/td&gt;&lt;td&gt;8.2 pp&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555202&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Angelic Observer&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.048&lt;/td&gt;&lt;td&gt;0.031&lt;/td&gt;&lt;td&gt;-0.016&lt;/td&gt;&lt;td&gt;7.9 pp&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555445&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Scuttling Butler&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.021&lt;/td&gt;&lt;td&gt;0.016&lt;/td&gt;&lt;td&gt;-0.005&lt;/td&gt;&lt;td&gt;7.4 pp&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555351&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;High-Rise Sawjack&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.124&lt;/td&gt;&lt;td&gt;0.081&lt;/td&gt;&lt;td&gt;-0.042&lt;/td&gt;&lt;td&gt;7.1 pp&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555428&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Tainted Indulgence&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.059&lt;/td&gt;&lt;td&gt;0.063&lt;/td&gt;&lt;td&gt;+0.004&lt;/td&gt;&lt;td&gt;7.1 pp&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555437&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Chrome Cat&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.039&lt;/td&gt;&lt;td&gt;0.039&lt;/td&gt;&lt;td&gt;+0.000&lt;/td&gt;&lt;td&gt;7.0 pp&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555228&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Refuse to Yield&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.023&lt;/td&gt;&lt;td&gt;0.019&lt;/td&gt;&lt;td&gt;-0.003&lt;/td&gt;&lt;td&gt;6.6 pp&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555254&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Psionic Snoop&lt;/a&gt;&lt;/td&gt;&lt;td&gt;0.076&lt;/td&gt;&lt;td&gt;0.079&lt;/td&gt;&lt;td&gt;+0.003&lt;/td&gt;&lt;td&gt;6.5 pp&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;What’s my theory on why top players get more out of some of these cards?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Talking about
&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=590122&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Goldhound&lt;/a&gt;
again! Ok instead of talking about when to play it, let’s talk about how to play it. It’s a sneakily difficult card to play. In particular, there are likely going to come a few critical turns when it may (or may not) be correct to sac it to ramp into a spell. Best players are making better decisions on these key turns.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=446130&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Tavern Swindler&lt;/a&gt;
is a big LOL for me (Carl), in that Garrett Gardner and I just released [an entire podcast about this card](&lt;a href=&quot;https://mysticaldispute.com/episode/045-mystical-dispute-tavern-swindler-snc/&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;https://mysticaldispute.com/episode/045-mystical-dispute-tavern-swindler-snc/&lt;/a&gt;). In it, we believe that players are likely just activating the ability too often, and probably are not just relying on it as a 2/2 body often enough.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555202&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Angelic Observer&lt;/a&gt;
needs a TON of support before the card is playable. My guess is most of this win rate differential is deck building.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555437&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Chrome Cat&lt;/a&gt;
? It’s a metal cat. Very dense. I don’t know. Scrying is hard?&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=555228&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Refuse to Yield&lt;/a&gt;
always has the obvious play of untapping your creature and blocking to kill something, but it can be tricky to set up at times, and the best players probably have a better sense of when it’s worth the risk of getting blown out by instant speed removal.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;top-players-play-decks-when-its-right-to-play-them&quot;&gt;Top players play decks when it’s right to play them&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#top-players-play-decks-when-its-right-to-play-them&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The best players learn what’s best quickly. The plots below show what fraction of games were played with a given deck color, with each plot showing data from a different group. Only a subset of decks are shown for ease of reading. As we can see, the best players were quickest to adapt to how good Brokers and Azorious are and how infrequently you should be in Riveteers in SNC.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.17lands.com/assets/img/posts/2022-05-20-learning-from-the-best/SNC-bottom-daily.png&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.17lands.com/assets/img/posts/2022-05-20-learning-from-the-best/SNC-bottom-daily.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt; &lt;a href=&quot;https://blog.17lands.com/assets/img/posts/2022-05-20-learning-from-the-best/SNC-middle-daily.png&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.17lands.com/assets/img/posts/2022-05-20-learning-from-the-best/SNC-middle-daily.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt; &lt;a href=&quot;https://blog.17lands.com/assets/img/posts/2022-05-20-learning-from-the-best/SNC-top-daily.png&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.17lands.com/assets/img/posts/2022-05-20-learning-from-the-best/SNC-top-daily.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt; &lt;em&gt;Fig. 1: Daily deck popularity in SNC by group&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Better players are also earlier to recognize new opportunities due to a shifting metagame. In NEO, for example, the top players found mono-red as an opportunity much earlier than other players.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.17lands.com/assets/img/posts/2022-05-20-learning-from-the-best/NEO-bottom-daily.png&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.17lands.com/assets/img/posts/2022-05-20-learning-from-the-best/NEO-bottom-daily.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt; &lt;a href=&quot;https://blog.17lands.com/assets/img/posts/2022-05-20-learning-from-the-best/NEO-middle-daily.png&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.17lands.com/assets/img/posts/2022-05-20-learning-from-the-best/NEO-middle-daily.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt; &lt;a href=&quot;https://blog.17lands.com/assets/img/posts/2022-05-20-learning-from-the-best/NEO-top-daily.png&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.17lands.com/assets/img/posts/2022-05-20-learning-from-the-best/NEO-top-daily.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt; &lt;em&gt;Fig. 2: Deck popularity in NEO by group&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Overall, a lot of these point to one larger conclusion: many of the top players are likely more in-tune with much of the data you can find here on 17Lands. Not only do they use our tools to track their own data, but they also actively analyze which colors to play and which cards to draft based on the generally available data. Accessing our data gives them big insights early on that they can use to gain an advantage over the rest of their competition.&lt;/p&gt;
&lt;p&gt;These are just a few of the interesting tidbits unlocked with this new data segmentation. We hope the community will find and share many more insights too!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Do you want to help contribute data for analyses like these in the future? Check out our &lt;a href=&quot;https://www.17lands.com/getting_started&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Getting Started&lt;/a&gt; page to install the lightweight Arena tracker and get access to all of our deck, draft, and gameplay tracking!&lt;/p&gt; ]]></description>
    <pubDate>Fri, 24 Apr 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>Two Hard Things in Computer Science</title>
    <link>https://garden.linusboyle.cn/idea/20260423033518-Two-Hard-Things-in-Computer-Science</link>
    <guid>https://garden.linusboyle.cn/idea/20260423033518-Two-Hard-Things-in-Computer-Science</guid>
    <description><![CDATA[ &lt;p&gt;“There are only two hard things in Computer Science: cache invalidation and naming things.”&lt;/p&gt;
&lt;p&gt;—Phil Karlton&lt;/p&gt;
&lt;h2 id=&quot;related&quot;&gt;Related&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#related&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;../idea/cache-coherence&quot; class=&quot;internal alias&quot; data-slug=&quot;idea/cache-coherence&quot;&gt;cache coherence&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt; ]]></description>
    <pubDate>Thu, 23 Apr 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>coherence</title>
    <link>https://garden.linusboyle.cn/idea/coherence</link>
    <guid>https://garden.linusboyle.cn/idea/coherence</guid>
    <description><![CDATA[ &lt;blockquote&gt;
&lt;p&gt;Unless care is taken, a coherence problem can arise if multiple actors (e.g., multiple cores) have access to multiple copies of a datum (e.g., in multiple caches) and at least one access is a write.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;比如日历的同步，网页的同步等都可以算作考虑coherency的场景。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;coherence/consistency 都为一致性，但略有区别&lt;/p&gt;
&lt;h2 id=&quot;related&quot;&gt;Related&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#related&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;extracted from: &lt;a href=&quot;../idea/cache-coherence&quot; class=&quot;internal alias&quot; data-slug=&quot;idea/cache-coherence&quot;&gt;cache coherence&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt; ]]></description>
    <pubDate>Thu, 23 Apr 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>A Primer on Memory Consistency and Cache Coherence</title>
    <link>https://garden.linusboyle.cn/source/Zotero/nagarajanPrimerMemoryConsistency2020</link>
    <guid>https://garden.linusboyle.cn/source/Zotero/nagarajanPrimerMemoryConsistency2020</guid>
    <description><![CDATA[ &lt;h2 id=&quot;a-primer-on-memory-consistency-and-cache-coherence&quot;&gt;&lt;a href=&quot;zotero://select/library/items/IYTDS73B&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;A Primer on Memory Consistency and Cache Coherence&lt;/a&gt;&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#a-primer-on-memory-consistency-and-cache-coherence&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;ToRead&lt;/p&gt;
&lt;blockquote class=&quot;callout quote&quot; data-callout=&quot;quote&quot;&gt;
&lt;div class=&quot;callout-title&quot;&gt;
                  &lt;div class=&quot;callout-icon&quot;&gt;&lt;/div&gt;
                  &lt;div class=&quot;callout-title-inner&quot;&gt;&lt;p&gt;Cite&lt;/p&gt;&lt;/div&gt;
                  
                &lt;/div&gt;
&lt;div class=&quot;callout-content&quot;&gt;
&lt;div class=&quot;callout-content-inner&quot;&gt;
&lt;p&gt;Vijay Nagarajan, Daniel J. Sorin, Mark D. Hill, and David A. Wood. 2020. &lt;em&gt;A Primer on Memory Consistency and Cache Coherence&lt;/em&gt;. Springer International Publishing, Cham. &lt;a href=&quot;https://doi.org/10.1007/978-3-031-01764-3&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;https://doi.org/10.1007/978-3-031-01764-3&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;attachments&quot;&gt;Attachments&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#attachments&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;zotero://select/library/items/JUKMTUD5&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;全文&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;collections&quot;&gt;Collections&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#collections&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;zotero://select/library/collections/EANVVSUQ&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;A 计算机科学/5 形式化方法/Concurrency&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;zotero://select/library/collections/3XJTK7U5&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;A 计算机科学/1 系统结构/CXL/DSM投稿&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;annotations&quot;&gt;Annotations&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#annotations&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;As part of this consistency model&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;support, the hardware provides cache coherence (or coherence).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;It is worth stressing that unlike consistency which is an architectural specification that defines shared memory correctness, coherence is a means to supporting a consistency model&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Essentially, all of the variants make one processor’s write visible to the other processors by propagating the write to all caches&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;But protocols differ in when and how the syncing happens. There are two major classes of coherence protocols.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;In the second approach, the coherence protocol propagates writes to the caches asynchronously, while still honoring the consistency model.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;GPUs originally chose not to support hardware cache coherence, since GPUs are designed for embarrassingly parallel graphics workloads that do not synchronize or share data all that much. However, the absence of hardware cache coherence leads to programmability and/or performance challenges when GPUs are used for general-purpose workloads with fine-grained synchronization and data sharing&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;We classify these protocols into two categories based on the nature of their coherence interfaces—specifically, based on whether there is a clean separation of coherence from the consistency model or whether they are indivisible.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;writes are propagated synchronously, the first category presents an interface that is identical to that of an atomic memory system&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The cache coherence protocol abstracts away the caches completely and presents an illusion of atomic memory&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;In the second, more-recent category, writes are propagated asynchronously—a write can thus return before it has been made visible to all processors, thus allowing for stale values (in real time) to be observed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;coherence protocols in this class must ensure that the order in which writes are&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;eventually made visible adheres to the ordering rules mandated by the consistency model.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;We define coherence through the single-writer–multiple-reader (SWMR) invariant.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;note that it is possible to to enforce a variety of consistency models, including strong models such as SC and TSO, using this approach&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;This invariant states that the value of a memory location at the start of an epoch is the same as the value of the memory location at the end of its last read-write epoch.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;must appear to execute all threads’ loads and stores to a single memory location in a total order that respects the program order of each thread&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Per-location SC=COH&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This definition highlights an important distinction between coherence and consistency in the literature: coherence is specified on a per-memory location basis, whereas consistency is specified with respect to all memory locations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Power is assumed to be incomparable with respect to Alpha, ARM, RMO, and XC until someone proves that one is more relaxed than the other or that the two are equivalent.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;related-items&quot;&gt;Related Items&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#related-items&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt; ]]></description>
    <pubDate>Thu, 23 Apr 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>VPS 常见工具</title>
    <link>https://garden.linusboyle.cn/idea/VPS-%E5%B8%B8%E8%A7%81%E5%B7%A5%E5%85%B7</link>
    <guid>https://garden.linusboyle.cn/idea/VPS-%E5%B8%B8%E8%A7%81%E5%B7%A5%E5%85%B7</guid>
    <description><![CDATA[ &lt;h2 id=&quot;基础防护&quot;&gt;基础防护&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#基础防护&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;创建普通用户，加入sudo组&lt;/li&gt;
&lt;li&gt;sshd禁用密码登录、root登录&lt;/li&gt;
&lt;li&gt;修改ssh端口为高位&lt;/li&gt;
&lt;li&gt;安装fail2ban和ufw，开放80、443&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;评测&quot;&gt;评测&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#评测&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;无访问权限&quot;&gt;无访问权限&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#无访问权限&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;bgp.tools&lt;/li&gt;
&lt;li&gt;looking glass: nexttrace/traceroute&lt;/li&gt;
&lt;li&gt;disvps看延迟波动、线路等，以及各路评测&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;有访问权限&quot;&gt;有访问权限&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#有访问权限&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;IP质量检测脚本  &lt;code&gt;bash &amp;#x3C;(curl -Ls https://Check.Place) -I&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;线路质量检测脚本 &lt;code&gt;bash &amp;#x3C;(curl -Ls Net.Check.Place)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;流媒体解锁检测 &lt;code&gt;bash &amp;#x3C;(curl -L -s check.unlock.media)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;硬件检测 &lt;code&gt;bash &amp;#x3C;(curl -Ls Hardware.Check.Place)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt; ]]></description>
    <pubDate>Tue, 21 Apr 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>Everything We Know About the MTG Arena Log File in 2026</title>
    <link>https://garden.linusboyle.cn/source/clipped/Everything-We-Know-About-the-MTG-Arena-Log-File-in-2026</link>
    <guid>https://garden.linusboyle.cn/source/clipped/Everything-We-Know-About-the-MTG-Arena-Log-File-in-2026</guid>
    <description><![CDATA[ &lt;p&gt;When I started building &lt;a href=&quot;https://manasight.gg/?ref=blog.manasight.gg&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Manasight&lt;/a&gt; and needed to &lt;a href=&quot;https://github.com/manasight/manasight-parser?ref=blog.manasight.gg&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;parse the Arena log file&lt;/a&gt;, I based my initial design on existing community documentation. About half of my assumptions turned out to be wrong.&lt;/p&gt;
&lt;p&gt;API method names I pulled from older parsers didn’t exist in real logs. Game result detection worked differently than documented. A field I expected to be nested inside another was actually its sibling. An entire parser module I wrote had to be deleted because the log event it targeted doesn’t appear in real Player.log files. Parser projects from 2019–2022 documented a format that has changed substantially since, and community gists reference API endpoints that were removed years ago.&lt;/p&gt;
&lt;p&gt;This post is what I wish existed when I started. Everything here has been verified against current Arena logs as of early 2026.&lt;/p&gt;
&lt;h2 id=&quot;log-file-location&quot;&gt;Log File Location&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#log-file-location&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Arena writes a single log file per session. When you close and reopen the game, the previous session’s log is preserved as a backup.&lt;/p&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Platform&lt;/th&gt;&lt;th&gt;Log Path&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Windows&lt;/td&gt;&lt;td&gt;&lt;code&gt;%LOCALAPPDATA%Low\Wizards Of The Coast\MTGA\Player.log&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;macOS&lt;/td&gt;&lt;td&gt;&lt;code&gt;~/Library/Logs/Wizards Of The Coast/MTGA/Player.log&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Previous session&lt;/td&gt;&lt;td&gt;Same directory, &lt;code&gt;Player-prev.log&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Prerequisite: You must enable “Detailed Logs (Plugin Support)” in Options &gt; Account. Without this, the log contains only basic diagnostic output and none of the JSON game data that parsers need. This is the most common reason new users can’t get companion tools working.&lt;/p&gt;
&lt;p&gt;The log file used to be called &lt;code&gt;output_log.txt&lt;/code&gt; and lived in a different location (renamed in May 2020). If you’re reading older parser code and the paths don’t match, that’s why.&lt;/p&gt;
&lt;h2 id=&quot;log-structure&quot;&gt;Log Structure&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#log-structure&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The log isn’t a clean structured format. It’s a mix of plain text diagnostic lines and embedded JSON objects. Game-relevant entries are marked by the &lt;code&gt;[UnityCrossThreadLogger]&lt;/code&gt; header prefix. Other bracketed headers appear in the log (&lt;code&gt;[PhysX]&lt;/code&gt;, &lt;code&gt;[Manifest]&lt;/code&gt;, &lt;code&gt;[TaskLogger]&lt;/code&gt;, etc.) but contain engine diagnostics, not game data.&lt;/p&gt;
&lt;p&gt;A typical sequence looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[UnityCrossThreadLogger]3/11/2026 12:34:56 PM
==&gt; EventJoin {&quot;EventName&quot;:&quot;QuickDraft_MKM_20260307&quot;,&quot;Id&quot;:&quot;abc123&quot;}

[UnityCrossThreadLogger]3/11/2026 12:35:01 PM
{&quot;greToClientEvent&quot;:{&quot;greToClientMessages&quot;:[{&quot;type&quot;:&quot;GREMessageType_GameStateMessage&quot;,...}]}}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;JSON payloads can span multiple lines. Parsing requires accumulating lines between header boundaries and extracting JSON using brace-depth counting (tracking open/close braces while respecting string literals). A new &lt;code&gt;[UnityCrossThreadLogger]&lt;/code&gt; header signals the end of the previous entry.&lt;/p&gt;
&lt;p&gt;Lines before the first &lt;code&gt;[UnityCrossThreadLogger]&lt;/code&gt; header in a file are Unity engine boot diagnostics (Mono initialization, GPU info, assembly loading) and should be skipped.&lt;/p&gt;
&lt;p&gt;Arena writes timestamps in the user’s locale format. This creates a parsing challenge: the log uses multiple date/time formats depending on the player’s system settings, plus several machine-oriented formats inside JSON payloads.&lt;/p&gt;
&lt;p&gt;Formats observed in real logs:&lt;/p&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Format&lt;/th&gt;&lt;th&gt;Example&lt;/th&gt;&lt;th&gt;Where&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;US 12-hour&lt;/td&gt;&lt;td&gt;&lt;code&gt;3/11/2026 6:08:07 PM&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;[UnityCrossThreadLogger]&lt;/code&gt; header lines&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ISO 8601 + Z&lt;/td&gt;&lt;td&gt;&lt;code&gt;2026-03-11T22:48:34.663Z&lt;/code&gt;&lt;/td&gt;&lt;td&gt;JSON datetime fields (&lt;code&gt;progressedDateTimeUTC&lt;/code&gt;, &lt;code&gt;_dailyRewardResetTimestamp&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ISO 8601 + offset&lt;/td&gt;&lt;td&gt;&lt;code&gt;2026-03-11T18:25:33.906174-07:00&lt;/code&gt;&lt;/td&gt;&lt;td&gt;JSON &lt;code&gt;ServerTime&lt;/code&gt;, &lt;code&gt;lastRemotePing&lt;/code&gt; fields&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;.NET ticks&lt;/td&gt;&lt;td&gt;&lt;code&gt;639088754738962389&lt;/code&gt;&lt;/td&gt;&lt;td&gt;ClientToGRE &lt;code&gt;timestamp&lt;/code&gt; fields&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Epoch milliseconds&lt;/td&gt;&lt;td&gt;&lt;code&gt;1773278674334&lt;/code&gt;&lt;/td&gt;&lt;td&gt;GRE &lt;code&gt;timestamp&lt;/code&gt; fields&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;On European-locale systems, header timestamps likely use a day-first format (e.g., &lt;code&gt;11/03/2026 12:34:56&lt;/code&gt;), but I haven’t been able to verify this directly since all my test data comes from a US-locale system.&lt;/p&gt;
&lt;p&gt;This ambiguity is problematic: when the day is 12 or less, &lt;code&gt;3/7/2026&lt;/code&gt; could be March 7 (US) or July 3 (European). There is no reliable way to resolve this from the log alone. My parser uses a US-first convention and accepts the loss for ambiguous dates. When I have EU-based logs to validate with, I am considering updating the parser to take a locale hint to break the tie.&lt;/p&gt;
&lt;p&gt;Timestamps appear after the header prefix on the same line. If a header line has no parseable timestamp, store the event without one. Synthetic timestamps break deduplication and chronological ordering.&lt;/p&gt;
&lt;h2 id=&quot;client-api-messages&quot;&gt;Client API Messages&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#client-api-messages&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Outside of gameplay, the log records REST-style API calls between the Arena client and Wizards’ servers. These handle collection data, events, matchmaking, rank, and inventory.&lt;/p&gt;
&lt;p&gt;This is the section most existing documentation gets wrong. Older parsers describe a &lt;code&gt;Namespace.MethodName&lt;/code&gt; convention with endpoints like &lt;code&gt;PlayerInventory.GetPlayerInventory&lt;/code&gt; and &lt;code&gt;PlayerInventory.GetPlayerCardsV3&lt;/code&gt;. Most of those endpoints were removed in the August 2021 breaking change and never restored.&lt;/p&gt;
&lt;p&gt;Current logs use an arrow-delimited format:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[UnityCrossThreadLogger]==&gt; EventJoin {&quot;id&quot;:&quot;abc123&quot;,&quot;request&quot;:&quot;{\&quot;EventName\&quot;:\&quot;QuickDraft_MKM_20260307\&quot;}&quot;}

&amp;#x3C;== RankGetCombinedRankInfo(e1f2a3b4-5678-90cd-ef12-34567890abcd)
{&quot;constructedClass&quot;:&quot;Gold&quot;,&quot;constructedLevel&quot;:2,...}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;==&gt;&lt;/code&gt; marks a client request. &lt;code&gt;&amp;#x3C;==&lt;/code&gt; marks a server response, followed by a UUID in parentheses (matching the request’s &lt;code&gt;id&lt;/code&gt; field) and a JSON payload. Note that &lt;code&gt;==&gt;&lt;/code&gt; lines carry the &lt;code&gt;[UnityCrossThreadLogger]&lt;/code&gt; prefix, but &lt;code&gt;&amp;#x3C;==&lt;/code&gt; lines appear bare with no header prefix. Request payloads often contain string-escaped JSON nested inside a &lt;code&gt;request&lt;/code&gt; field.&lt;/p&gt;
&lt;h3 id=&quot;whats-available-in-2026&quot;&gt;What’s Available in 2026&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#whats-available-in-2026&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;













































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Direction&lt;/th&gt;&lt;th&gt;Method&lt;/th&gt;&lt;th&gt;What It Contains&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;==&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;EventJoin&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Player joins an event&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;==&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;EventClaimPrize&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Prize claim after an event&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;==&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;EventEnterPairing&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Player enters matchmaking&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;#x3C;==&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;RankGetCombinedRankInfo&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Constructed and Limited rank, tier, level&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;#x3C;==&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;StartHook&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Startup data: inventory (gold, gems, wildcards), deck summaries, card metadata, server time&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;==&gt;&lt;/code&gt; / &lt;code&gt;&amp;#x3C;==&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;DraftCompleteDraft&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Human draft completion (request and response)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;==&gt;&lt;/code&gt; / &lt;code&gt;&amp;#x3C;==&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;BotDraftDraftPick&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Bot draft pack presentation and pick selection&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;code&gt;StartHook&lt;/code&gt; is the primary startup data delivery mechanism. It arrives as a single large response containing &lt;code&gt;InventoryInfo&lt;/code&gt; (gold, gems, wildcards, vault progress), &lt;code&gt;DeckSummariesV2&lt;/code&gt;, &lt;code&gt;CardMetadataInfo&lt;/code&gt;, and a dozen other fields. Notably, the player’s card collection (owned cards) does not appear in any &lt;code&gt;==&gt;&lt;/code&gt; / &lt;code&gt;&amp;#x3C;==&lt;/code&gt; API call in current logs. The old &lt;code&gt;GetPlayerCardsV3&lt;/code&gt; endpoint was removed in August 2021 and was not replaced with an equivalent in this API layer.&lt;/p&gt;
&lt;p&gt;A complete catalog of every API method that can appear in the log doesn’t exist. You discover new ones by watching the log during different game activities.&lt;/p&gt;
&lt;h2 id=&quot;gre-messages&quot;&gt;GRE Messages&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#gre-messages&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;GRE (Game Rules Engine) messages contain the actual game data: every card, zone, phase transition, and player action. This is what makes deck tracking, action logs, and replay viewers possible.&lt;/p&gt;
&lt;p&gt;GRE messages are wrapped in a &lt;code&gt;greToClientEvent&lt;/code&gt; envelope:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;json&quot; data-theme=&quot;github-light github-dark&quot;&gt;&lt;code data-language=&quot;json&quot; data-theme=&quot;github-light github-dark&quot; style=&quot;display: grid;&quot;&gt;&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;greToClientEvent&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    &quot;greToClientMessages&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      {&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;GREMessageType_GameStateMessage&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        &quot;gameStateMessage&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: { &lt;/span&gt;&lt;span style=&quot;--shiki-light:#B31D28;--shiki-light-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    ]&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;h3 id=&quot;gre-message-types&quot;&gt;GRE Message Types&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#gre-message-types&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;









































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;GREMessageType_ConnectResp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Initial connection response with starting game state&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;GREMessageType_GameStateMessage&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Full or partial game state update&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;GREMessageType_QueuedGameStateMessage&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Queued state update (same structure as above)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;GREMessageType_TimerStateMessage&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Rope timers and timeout info&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;GREMessageType_IntermissionReq&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Between-game transition in Bo3 (contains game result)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;GREMessageType_SubmitDeckReq&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Sideboarding prompt between Bo3 games&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;GREMessageType_UIMessage&lt;/code&gt;&lt;/td&gt;&lt;td&gt;UI-related noise&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;GREMessageType_SetSettingsResp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Settings acknowledgment&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id=&quot;client-to-gre-messages&quot;&gt;Client-to-GRE Messages&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#client-to-gre-messages&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Player actions also appear in the log:&lt;/p&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ClientMessageType_MulliganResp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Keep or mulligan decision&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ClientMessageType_SelectNResp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Card selection (e.g., discard, scry ordering)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;ClientToGREUIMessage&lt;/code&gt;&lt;/td&gt;&lt;td&gt;UI interactions (hover, chat). Noise.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Some client-to-GRE payloads contain string-escaped JSON nested inside JSON. Your parser needs to handle both already-parsed objects and string-encoded payloads that need a second deserialization pass.&lt;/p&gt;
&lt;h2 id=&quot;gamestatemessage&quot;&gt;GameStateMessage&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#gamestatemessage&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is the core data structure. Each &lt;code&gt;GameStateMessage&lt;/code&gt; contains some or all of these fields:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;json&quot; data-theme=&quot;github-light github-dark&quot;&gt;&lt;code data-language=&quot;json&quot; data-theme=&quot;github-light github-dark&quot; style=&quot;display: grid;&quot;&gt;&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;gameStateMessage&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    &quot;gameObjects&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: [ &lt;/span&gt;&lt;span style=&quot;--shiki-light:#B31D28;--shiki-light-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ],&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    &quot;zones&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: [ &lt;/span&gt;&lt;span style=&quot;--shiki-light:#B31D28;--shiki-light-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ],&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    &quot;gameInfo&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;      &quot;stage&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;GameStage_Play&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;      &quot;matchState&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;MatchState_GameInProgress&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    &quot;turnInfo&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;      &quot;turnNumber&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;      &quot;phase&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;Phase_Main1&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;      &quot;activePlayer&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;      &quot;decisionPlayer&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    &quot;annotations&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: [ &lt;/span&gt;&lt;span style=&quot;--shiki-light:#B31D28;--shiki-light-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ],&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    &quot;timers&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: [ &lt;/span&gt;&lt;span style=&quot;--shiki-light:#B31D28;--shiki-light-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ],&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    &quot;diffDeletedInstanceIds&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: [ &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;101&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;202&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ]&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Note that &lt;code&gt;turnInfo&lt;/code&gt; is a sibling of &lt;code&gt;gameInfo&lt;/code&gt;, not nested inside it. I initially had it as &lt;code&gt;gameStateMessage.gameInfo.turnInfo&lt;/code&gt;, which returned null every time. This is the kind of structural assumption that only breaks when you test against real data.&lt;/p&gt;
&lt;h3 id=&quot;key-fields&quot;&gt;Key Fields&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#key-fields&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;**gameObjects**&lt;/code&gt;: Every card and permanent in the game. Each object has an &lt;code&gt;instanceId&lt;/code&gt;, &lt;code&gt;grpId&lt;/code&gt; (the card’s global ID), &lt;code&gt;zoneId&lt;/code&gt;, &lt;code&gt;ownerSeatId&lt;/code&gt;, &lt;code&gt;controllerSeatId&lt;/code&gt;, &lt;code&gt;visibility&lt;/code&gt;, &lt;code&gt;cardTypes&lt;/code&gt;, &lt;code&gt;subtypes&lt;/code&gt;, &lt;code&gt;power&lt;/code&gt;, &lt;code&gt;toughness&lt;/code&gt;, and more. The &lt;code&gt;name&lt;/code&gt; field is a numeric ID, not a human-readable string; card names require a separate database lookup. Tracking zone transitions of game objects is how you build a deck tracker.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;**zones**&lt;/code&gt;: Library, hand, battlefield, graveyard, exile, stack, and others. Each zone has a &lt;code&gt;zoneId&lt;/code&gt;, &lt;code&gt;type&lt;/code&gt; (e.g., &lt;code&gt;ZoneType_Hand&lt;/code&gt;), &lt;code&gt;ownerSeatId&lt;/code&gt;, and &lt;code&gt;objectInstanceIds&lt;/code&gt; listing what’s in it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;annotations&lt;/code&gt;&lt;/strong&gt;: Records of game actions: zone transfers, damage, counters, life total changes. The format is less intuitive than you’d expect (see next section).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;timers&lt;/code&gt;&lt;/strong&gt;: Rope timer state, timeout counts, priority timing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;diffDeletedInstanceIds&lt;/code&gt;&lt;/strong&gt;: Instance IDs that should be purged from your local game state. When Arena sends incremental updates (not full state snapshots), this field tells you what no longer exists. If you don’t process this, your tracker will show phantom cards.&lt;/p&gt;
&lt;h3 id=&quot;full-state-vs-incremental-updates&quot;&gt;Full State vs. Incremental Updates&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#full-state-vs-incremental-updates&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;GameStateMessage&lt;/code&gt; can be a full state snapshot or a partial delta containing only what changed. There’s no explicit flag that distinguishes them. In practice, early messages in a game (especially from &lt;code&gt;ConnectResp&lt;/code&gt;) tend to be full snapshots, and subsequent messages tend to be deltas. Your parser needs to merge incoming fields into a running game state and remove anything listed in &lt;code&gt;diffDeletedInstanceIds&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;annotations&quot;&gt;Annotations&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#annotations&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Annotations record game actions within a &lt;code&gt;GameStateMessage&lt;/code&gt;. Their format is worth calling out because it’s less intuitive than the rest of the GRE schema.&lt;/p&gt;
&lt;p&gt;You might expect named wrapper objects with camelCase fields. What Arena actually writes:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;json&quot; data-theme=&quot;github-light github-dark&quot;&gt;&lt;code data-language=&quot;json&quot; data-theme=&quot;github-light github-dark&quot; style=&quot;display: grid;&quot;&gt;&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;id&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;47&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;affectorId&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;312&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;affectedIds&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;455&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;type&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;AnnotationType_ZoneTransfer&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;details&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    { &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;zone_src&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;KeyValuePairValueType_int32&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;valueInt32&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;29&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;] },&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    { &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;zone_dest&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;KeyValuePairValueType_int32&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;valueInt32&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;31&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;] },&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    { &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;category&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;KeyValuePairValueType_string&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;valueString&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;PlayLand&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;] }&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Two surprises here. First, &lt;code&gt;type&lt;/code&gt; is an &lt;strong&gt;array of strings&lt;/strong&gt;, not a plain string. In every annotation I’ve seen in current logs, it’s a single-element array, but the array wrapper is always present.&lt;/p&gt;
&lt;p&gt;Second, the data lives in a uniform &lt;code&gt;details&lt;/code&gt; array of key-value pairs, each with a typed value field (&lt;code&gt;valueInt32&lt;/code&gt;, &lt;code&gt;valueString&lt;/code&gt;, etc.). The key names use &lt;code&gt;snake_case&lt;/code&gt; (&lt;code&gt;zone_src&lt;/code&gt;, &lt;code&gt;orig_id&lt;/code&gt;, &lt;code&gt;new_id&lt;/code&gt;), not camelCase. You need helper functions to search the details array by key name.&lt;/p&gt;
&lt;p&gt;Annotation types include &lt;code&gt;AnnotationType_ZoneTransfer&lt;/code&gt;, &lt;code&gt;AnnotationType_ObjectIdChanged&lt;/code&gt;, &lt;code&gt;AnnotationType_ResolutionComplete&lt;/code&gt;, &lt;code&gt;AnnotationType_DamageDealt&lt;/code&gt;, &lt;code&gt;AnnotationType_ModifiedLife&lt;/code&gt;, &lt;code&gt;AnnotationType_CounterAdded&lt;/code&gt;, &lt;code&gt;AnnotationType_PhaseOrStepModified&lt;/code&gt;, &lt;code&gt;AnnotationType_TappedUntappedPermanent&lt;/code&gt;, and others.&lt;/p&gt;
&lt;h2 id=&quot;message-batching&quot;&gt;Message Batching&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#message-batching&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is the implementation detail I most wish someone had told me upfront.&lt;/p&gt;
&lt;p&gt;Arena frequently batches multiple &lt;code&gt;GameStateMessage&lt;/code&gt; values into a single &lt;code&gt;greToClientMessages&lt;/code&gt; array. In my testing across multiple play sessions, over half of all GRE events that contain game state data have two or more &lt;code&gt;GameStateMessage&lt;/code&gt; entries bundled together. A single log entry might contain three or four game state updates.&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;json&quot; data-theme=&quot;github-light github-dark&quot;&gt;&lt;code data-language=&quot;json&quot; data-theme=&quot;github-light github-dark&quot; style=&quot;display: grid;&quot;&gt;&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;greToClientEvent&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    &quot;greToClientMessages&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      { &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;GREMessageType_GameStateMessage&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;gameStateMessage&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: { &lt;/span&gt;&lt;span style=&quot;--shiki-light:#B31D28;--shiki-light-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; } },&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      { &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;GREMessageType_GameStateMessage&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;gameStateMessage&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: { &lt;/span&gt;&lt;span style=&quot;--shiki-light:#B31D28;--shiki-light-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; } },&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      { &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;GREMessageType_QueuedGameStateMessage&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;gameStateMessage&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: { &lt;/span&gt;&lt;span style=&quot;--shiki-light:#B31D28;--shiki-light-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; } }&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    ]&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;If you use a find-first approach to extract the &lt;code&gt;GameStateMessage&lt;/code&gt; from this array, you silently discard the rest. In my case, the parser was missing turn changes, creature deaths, and annotation data until I refactored it to iterate every message in the batch. This was the source of most of my “why is the tracker missing data” bugs.&lt;/p&gt;
&lt;h2 id=&quot;match-lifecycle&quot;&gt;Match Lifecycle&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#match-lifecycle&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;match-start&quot;&gt;Match Start&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#match-start&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Match boundaries come from &lt;code&gt;matchGameRoomStateChangedEvent&lt;/code&gt; JSON entries:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;json&quot; data-theme=&quot;github-light github-dark&quot;&gt;&lt;code data-language=&quot;json&quot; data-theme=&quot;github-light github-dark&quot; style=&quot;display: grid;&quot;&gt;&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;matchGameRoomStateChangedEvent&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    &quot;gameRoomInfo&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;      &quot;stateType&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;MatchGameRoomStateType_Playing&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;      &quot;gameRoomConfig&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        &quot;matchId&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;abc123&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        &quot;eventId&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;Constructed_BestOf1&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        &quot;reservedPlayers&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;          { &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;systemSeatId&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;userId&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;playerName&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;          { &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;systemSeatId&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;userId&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;playerName&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        ]&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;This gives you the match ID, event type, and both players’ seat assignments.&lt;/p&gt;
&lt;h3 id=&quot;game-result&quot;&gt;Game Result&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#game-result&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Game results are embedded in GRE &lt;code&gt;GameStateMessage&lt;/code&gt; payloads, not in a separate event type. When a game ends, the &lt;code&gt;gameInfo&lt;/code&gt; field inside a &lt;code&gt;GameStateMessage&lt;/code&gt; transitions to:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;json&quot; data-theme=&quot;github-light github-dark&quot;&gt;&lt;code data-language=&quot;json&quot; data-theme=&quot;github-light github-dark&quot; style=&quot;display: grid;&quot;&gt;&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;stage&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;GameStage_GameOver&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;matchState&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;MatchState_GameComplete&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;results&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    { &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;scope&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;MatchScope_Game&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;result&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;ResultType_WinLoss&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;winningTeamId&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;reason&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;ResultReason_Game&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;There’s a catch: Arena sends &lt;strong&gt;two&lt;/strong&gt; &lt;code&gt;GameStage_GameOver&lt;/code&gt; messages per game end. The first has &lt;code&gt;matchState: &quot;MatchState_GameComplete&quot;&lt;/code&gt; (game-scope result). The second has &lt;code&gt;matchState: &quot;MatchState_MatchComplete&quot;&lt;/code&gt; (match-scope result, which also includes both &lt;code&gt;MatchScope_Game&lt;/code&gt; and &lt;code&gt;MatchScope_Match&lt;/code&gt; entries). If you emit a game result event for both, you get duplicates. Filter on &lt;code&gt;MatchState_GameComplete&lt;/code&gt; and skip &lt;code&gt;MatchState_MatchComplete&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I initially built a separate game result parser around &lt;code&gt;LogBusinessEvents&lt;/code&gt; entries with a &lt;code&gt;WinningType&lt;/code&gt; field, based on documentation from older parsers. That event never appeared in any real log I tested. The entire module had to be deleted.&lt;/p&gt;
&lt;h3 id=&quot;match-complete&quot;&gt;Match Complete&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#match-complete&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Match completion uses the same &lt;code&gt;matchGameRoomStateChangedEvent&lt;/code&gt; structure:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;json&quot; data-theme=&quot;github-light github-dark&quot;&gt;&lt;code data-language=&quot;json&quot; data-theme=&quot;github-light github-dark&quot; style=&quot;display: grid;&quot;&gt;&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;matchGameRoomStateChangedEvent&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    &quot;gameRoomInfo&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;      &quot;stateType&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;MatchGameRoomStateType_MatchCompleted&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;      &quot;finalMatchResult&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        &quot;matchId&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;abc123&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        &quot;matchCompletedReason&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;MatchCompletedReasonType_Success&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        &quot;resultList&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;          { &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;scope&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;MatchScope_Game&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;result&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;ResultType_WinLoss&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;winningTeamId&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;          { &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;scope&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;MatchScope_Match&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;result&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;ResultType_WinLoss&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;&quot;winningTeamId&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        ]&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;For Bo3 matches, &lt;code&gt;resultList&lt;/code&gt; contains one &lt;code&gt;MatchScope_Game&lt;/code&gt; entry per game played, plus a final &lt;code&gt;MatchScope_Match&lt;/code&gt; entry for the overall result. In a 2-0 match, for example, the list contains three entries: two game-scope results and one match-scope result. Between games, the GRE sends &lt;code&gt;GREMessageType_IntermissionReq&lt;/code&gt; (containing the game result) followed by &lt;code&gt;GREMessageType_SubmitDeckReq&lt;/code&gt; for sideboarding.&lt;/p&gt;
&lt;h2 id=&quot;draft-events&quot;&gt;Draft Events&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#draft-events&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Draft parsing requires handling two completely different log formats depending on the draft type.&lt;/p&gt;
&lt;h3 id=&quot;bot-drafts-quick-draft&quot;&gt;Bot Drafts (Quick Draft)&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#bot-drafts-quick-draft&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Bot draft messages use a &lt;code&gt;CurrentModule&lt;/code&gt; / &lt;code&gt;Payload&lt;/code&gt; envelope, where the payload is string-escaped JSON. Pack presentation arrives as a &lt;code&gt;BotDraftDraftPick&lt;/code&gt; response:&lt;/p&gt;
&lt;figure data-rehype-pretty-code-figure=&quot;&quot;&gt;&lt;pre tabindex=&quot;0&quot; data-language=&quot;json&quot; data-theme=&quot;github-light github-dark&quot;&gt;&lt;code data-language=&quot;json&quot; data-theme=&quot;github-light github-dark&quot; style=&quot;display: grid;&quot;&gt;&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;CurrentModule&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;BotDraft&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  &quot;Payload&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;{&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Result&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Success&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;EventName&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;QuickDraft_ECL_20260223&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;DraftStatus&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;PickNext&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;PackNumber&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;:0,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;PickNumber&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;:0,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;NumCardsToPick&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;:1,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;DraftPack&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;:[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;98361&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;98498&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;98358&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;,...],&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;PickedCards&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;:[...]}&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span data-line=&quot;&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;Note that &lt;code&gt;DraftPack&lt;/code&gt; is an array of &lt;strong&gt;strings&lt;/strong&gt;, not integers. Same for &lt;code&gt;PickedCards&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Pick selection is sent as a &lt;code&gt;==&gt; BotDraftDraftPick&lt;/code&gt; request (no underscore) with &lt;code&gt;PickInfo&lt;/code&gt; containing the chosen &lt;code&gt;CardIds&lt;/code&gt; (plural, an array), &lt;code&gt;PackNumber&lt;/code&gt;, and &lt;code&gt;PickNumber&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;==&gt; BotDraftDraftPick {&quot;id&quot;:&quot;...&quot;,&quot;request&quot;:&quot;{\&quot;EventName\&quot;:\&quot;QuickDraft_ECL_20260223\&quot;,\&quot;PickInfo\&quot;:{\&quot;EventName\&quot;:\&quot;QuickDraft_ECL_20260223\&quot;,\&quot;CardIds\&quot;:[\&quot;98546\&quot;],\&quot;PackNumber\&quot;:0,\&quot;PickNumber\&quot;:0}}&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Draft completion for bot drafts does &lt;strong&gt;not&lt;/strong&gt; use &lt;code&gt;DraftCompleteDraft&lt;/code&gt;. Instead, the final &lt;code&gt;BotDraftDraftPick&lt;/code&gt; response returns &lt;code&gt;&quot;DraftStatus&quot;:&quot;Completed&quot;&lt;/code&gt; with a full &lt;code&gt;PickedCards&lt;/code&gt; array and an empty &lt;code&gt;DraftPack&lt;/code&gt;. The response also includes &lt;code&gt;DTO_InventoryInfo&lt;/code&gt; with card grant details.&lt;/p&gt;
&lt;h3 id=&quot;human-drafts-premiertraditional&quot;&gt;Human Drafts (Premier/Traditional)&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#human-drafts-premiertraditional&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Pack presentation uses a &lt;code&gt;Draft.Notify&lt;/code&gt; entry with &lt;code&gt;draftId&lt;/code&gt;, &lt;code&gt;SelfPack&lt;/code&gt;, &lt;code&gt;SelfPick&lt;/code&gt;, and &lt;code&gt;PackCards&lt;/code&gt; (a comma-separated string of card IDs, not an array). One caveat: the very first pick of pack 1 does not generate a &lt;code&gt;Draft.Notify&lt;/code&gt;. The first one appears at &lt;code&gt;SelfPick:2&lt;/code&gt;. New packs (pack 2 and pack 3) do generate &lt;code&gt;Draft.Notify&lt;/code&gt; for their first pick.&lt;/p&gt;
&lt;p&gt;Pick selection arrives as &lt;code&gt;EventPlayerDraftMakePick&lt;/code&gt; with &lt;code&gt;DraftId&lt;/code&gt;, &lt;code&gt;GrpIds&lt;/code&gt; (an array of selected card IDs), &lt;code&gt;Pack&lt;/code&gt;, and &lt;code&gt;Pick&lt;/code&gt; numbers. In formats that allow picking multiple cards (like Pick Two Draft), &lt;code&gt;GrpIds&lt;/code&gt; contains more than one entry.&lt;/p&gt;
&lt;h3 id=&quot;draft-completion&quot;&gt;Draft Completion&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#draft-completion&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Human drafts emit a &lt;code&gt;DraftCompleteDraft&lt;/code&gt; entry when the draft finishes. Note the exact name: no underscore between “Draft” and “Complete.” The request contains &lt;code&gt;EventName&lt;/code&gt; and &lt;code&gt;IsBotDraft: false&lt;/code&gt; in string-escaped JSON. The response includes &lt;code&gt;CourseId&lt;/code&gt;, &lt;code&gt;InternalEventName&lt;/code&gt;, and &lt;code&gt;CardPool&lt;/code&gt; (an array of integer card IDs — the complete pool of drafted cards).&lt;/p&gt;
&lt;p&gt;Bot drafts (QuickDraft) do &lt;strong&gt;not&lt;/strong&gt; emit &lt;code&gt;DraftCompleteDraft&lt;/code&gt;. Completion is signaled by the final &lt;code&gt;BotDraftDraftPick&lt;/code&gt; response with &lt;code&gt;DraftStatus: &quot;Completed&quot;&lt;/code&gt; (see above).&lt;/p&gt;
&lt;h2 id=&quot;session-events&quot;&gt;Session Events&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#session-events&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A few log events track the player session:&lt;/p&gt;

















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Signature&lt;/th&gt;&lt;th&gt;What It Contains&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;authenticateResponse&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Login confirmation with &lt;code&gt;clientId&lt;/code&gt;, &lt;code&gt;sessionId&lt;/code&gt;, and &lt;code&gt;screenName&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;FrontDoorConnection.Close&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Logout or disconnect (includes reason, e.g., &lt;code&gt;&quot;OnDestroy&quot;&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;code&gt;authenticateResponse&lt;/code&gt; is the primary source of player identity. It appears at session start and again on each match server reconnection. Identity data also appears in &lt;code&gt;matchGameRoomStateChangedEvent&lt;/code&gt;, where the &lt;code&gt;reservedPlayers&lt;/code&gt; array includes &lt;code&gt;userId&lt;/code&gt; and &lt;code&gt;playerName&lt;/code&gt; for both players in a match.&lt;/p&gt;
&lt;p&gt;If you’re building a tool that processes this data, strip or hash identity fields before anything leaves the user’s machine. WotC has been moving in this direction themselves: screen names were removed from most log entries in July 2021, and opponent display name tags were removed in July 2024 (see the breaking changes timeline below). Treat the remaining identity fields as data you have access to, not data you’re entitled to store or transmit.&lt;/p&gt;
&lt;h2 id=&quot;gap-between-log-and-ui&quot;&gt;Gap Between Log and UI&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#gap-between-log-and-ui&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is what got me interested in the project. Arena has all this data. The log proves it. But the game client surfaces almost none of it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Win rates:&lt;/strong&gt; Every match result is logged. Arena never shows your win rate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Match history:&lt;/strong&gt; Every game is recorded. Arena shows nothing after you close the results screen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Action sequences:&lt;/strong&gt; The GRE logs every trigger, every scry result, every combat step. Arena’s in-game log auto-scrolls and clears within seconds.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Revealed cards:&lt;/strong&gt; When your opponent plays or reveals a card, the GRE logs the full card data. Arena doesn’t surface a history of what’s been revealed during the current game.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Arena is a game client designed to keep you playing, not to surface analytics. That’s a reasonable design choice, but it means there’s a permanent structural gap between what the game records and what it shows you. That’s what I’m building &lt;a href=&quot;https://manasight.gg/?ref=blog.manasight.gg&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Manasight&lt;/a&gt; to address.&lt;/p&gt;
&lt;h2 id=&quot;manasight&quot;&gt;Manasight&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#manasight&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The parser described in this post is &lt;a href=&quot;https://github.com/manasight/manasight-parser?ref=blog.manasight.gg&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;open source&lt;/a&gt;, and it’s the foundation for everything below.&lt;/p&gt;
&lt;p&gt;The first thing I’m building is a desktop overlay with a scrollable action log, a deck tracker, and a connection health indicator. The action log will be comprehensive: every spell, trigger, scry result, and combat assignment captured in real time, persistent and searchable instead of flashing on screen and disappearing. After that, turn-by-turn game replays.&lt;/p&gt;
&lt;p&gt;Manasight will run on both Windows and Mac, track all formats, and the core features will be free. It’s a lightweight standalone app built with &lt;a href=&quot;https://v2.tauri.app/?ref=blog.manasight.gg&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Tauri&lt;/a&gt;, not a browser extension.&lt;/p&gt;
&lt;p&gt;On data: the same care I described in the session events section will apply to Manasight. You’ll know what’s collected, you’ll be able to turn it off, and delete means delete. The parser is open source so you can verify exactly what it reads.&lt;/p&gt;
&lt;p&gt;I’ll be writing more about the technical challenges as I build. If you’re interested in Arena tooling or building on game data, follow along on &lt;a href=&quot;https://blog.manasight.gg/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;the blog&lt;/a&gt; or on &lt;a href=&quot;https://x.com/manasightgg?ref=blog.manasight.gg&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Twitter/X&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;appendix&quot;&gt;Appendix&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#appendix&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;hr&gt;
&lt;h3 id=&quot;breaking-changes&quot;&gt;Breaking Changes&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#breaking-changes&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Fair warning: the log format is unstable and has broken without notice before.&lt;/p&gt;
&lt;p&gt;In the 2021.8.0.3855 update, Wizards removed several log endpoints without warning:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PlayerInventory.GetPlayerInventory&lt;/code&gt;: removed&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PlayerInventory.GetPlayerCardsV3&lt;/code&gt;: removed&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Inventory.Updated&lt;/code&gt;: removed&lt;/li&gt;
&lt;li&gt;Several draft-related endpoints: removed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Collection tracking, inventory updates, and draft pick logging all broke overnight. A &lt;a href=&quot;https://web.archive.org/web/20251109061807/https://feedback.wizards.com/forums/918667-mtg-arena-bugs-product-suggestions/suggestions/44050746-broken-logs-in-2021-8-0-3855&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;community feedback thread&lt;/a&gt; collected over 700 votes. Some data eventually reappeared through different endpoints (inventory now comes through &lt;code&gt;StartHook&lt;/code&gt;), but the format changed and old parsers needed rewrites. Card collection data (&lt;code&gt;GetPlayerCardsV3&lt;/code&gt;) was not replaced with an equivalent in the current API layer.&lt;/p&gt;
&lt;p&gt;That wasn’t an isolated incident. A timeline of data removals:&lt;/p&gt;

































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date&lt;/th&gt;&lt;th&gt;What Changed&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Sept 2019&lt;/td&gt;&lt;td&gt;Vault progress info removed&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;May 2020&lt;/td&gt;&lt;td&gt;Log file renamed from &lt;code&gt;output_log.txt&lt;/code&gt; to &lt;code&gt;Player.log&lt;/code&gt;, path changed&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;July 2021&lt;/td&gt;&lt;td&gt;Screen name removed from most log entries&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Aug 2021&lt;/td&gt;&lt;td&gt;Collection, inventory, and draft endpoints removed (partially restored later in new format)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Aug 2022&lt;/td&gt;&lt;td&gt;MMR/rating data removed&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;July 2024&lt;/td&gt;&lt;td&gt;Opponent display name tag removed&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The trend is clear: Wizards has been reducing the data available in the log over time, not expanding it. If you’re building a tool that depends on the log, design for resilience. Assume any field can disappear in the next patch. Anything your parser extracts today might not be there tomorrow.&lt;/p&gt;
&lt;h3 id=&quot;open-source-parsers&quot;&gt;Open-Source Parsers&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#open-source-parsers&quot; class=&quot;internal&quot;&gt;&lt;svg width=&quot;18&quot; height=&quot;18&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;path d=&quot;M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71&quot;&gt;&lt;/path&gt;&lt;path d=&quot;M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you’re building something, start by reading existing implementations.&lt;/p&gt;
&lt;p&gt;Status as of early 2026:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/manasight/manasight-parser?ref=blog.manasight.gg&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;manasight-parser&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;Rust · Active&lt;/strong&gt; My project. Verified against current logs. Full GRE, client API, draft, and match lifecycle parsing. MIT/Apache-2.0.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/rconroy293/mtga-log-client?ref=blog.manasight.gg&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;rconroy293/mtga-log-client&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;Python · Active&lt;/strong&gt; 17Lands’ official client. Clean, focused on draft and game event upload.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/gathering-gg/parser?ref=blog.manasight.gg&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;gathering-gg/parser&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;Go · Unmaintained (2019)&lt;/strong&gt; Comprehensively typed. Good for understanding message structures, but the format has changed.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/mtgatool/mtgatool-desktop?ref=blog.manasight.gg&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;mtgatool/mtgatool-desktop&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;TypeScript · Low activity (last release Oct 2024)&lt;/strong&gt; Full Electron app with log watcher and message dispatcher.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/mtgatracker/mtgatracker?ref=blog.manasight.gg&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;mtgatracker/mtgatracker&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;Python · Unmaintained (2020)&lt;/strong&gt; Websocket-based overlay. Historical reference.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/Razviar/mtgap?ref=blog.manasight.gg&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;Razviar/mtgap&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;TypeScript · Archived (April 2025)&lt;/strong&gt; MTGA Pro Tracker. Rewrote its parser multiple times as the format evolved.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/riQQ/MtgaProto?ref=blog.manasight.gg&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;riQQ/MtgaProto&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;Protobuf · Updated periodically&lt;/strong&gt; Extracted &lt;code&gt;.proto&lt;/code&gt; definitions from Arena’s installation files. Reference, not a parser.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Manasight is not affiliated with, endorsed by, or sponsored by Wizards of the Coast or Hasbro.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Have corrections or additions? I’d love to hear from other developers working in this space.&lt;/em&gt;&lt;/p&gt; ]]></description>
    <pubDate>Mon, 20 Apr 2026 00:00:00 GMT</pubDate>
  </item>
    </channel>
  </rss>