<?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>Sun, 06 Sep 2026 07:29:10 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>Sun, 06 Sep 2026 07:29:10 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>Sun, 06 Sep 2026 07:29:10 GMT</pubDate>
  </item><item>
    <title>喀耳刻</title>
    <link>https://garden.linusboyle.cn/source/book/%E5%96%80%E8%80%B3%E5%88%BB</link>
    <guid>https://garden.linusboyle.cn/source/book/%E5%96%80%E8%80%B3%E5%88%BB</guid>
    <description><![CDATA[ &lt;p&gt;如果按照女性主义的视角，喀耳刻在本书中是站在父权的对立面，后者主要是以希腊诸神和奥德修斯这样的凡人为代表的。从一开始和普罗米修斯的相识就能看出，喀耳刻对于凡人的态度不一样。她会认罪、为自己的过失感到愧疚，为自己的儿子担惊受怕等等。总体上来说，这是一个虽然有巫术，但其实相当接近凡人的角色。&lt;/p&gt;
&lt;p&gt;当然，本书在宣传的时候强调这是希腊神话在现代女性主义下的重写。这更像是一种营销的口号而非事实。本书描写了一个活生生的人，而这个人恰好是个女人。这里面带有典型女性主义特征的地方其实并不多。事实上，把它看作一本写得不错的奇幻小说就可以了。&lt;/p&gt; ]]></description>
    <pubDate>Sun, 06 Sep 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>欢迎来龙餐馆</title>
    <link>https://garden.linusboyle.cn/source/video/%E6%AC%A2%E8%BF%8E%E6%9D%A5%E9%BE%99%E9%A4%90%E9%A6%86</link>
    <guid>https://garden.linusboyle.cn/source/video/%E6%AC%A2%E8%BF%8E%E6%9D%A5%E9%BE%99%E9%A4%90%E9%A6%86</guid>
    <description><![CDATA[ &lt;p&gt;一部以中国人的旁观视角的反战题材电影，沈腾一反刻板影响，出演了徐福这一并不特别搞笑的角色。整体的节奏很好，拍摄技法也很到位，结尾也留出了悬念，总体是一部不可多得的好电影。&lt;/p&gt; ]]></description>
    <pubDate>Sun, 30 Aug 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>缓存一致性与内存模型的关系</title>
    <link>https://garden.linusboyle.cn/idea/20260821024532-%E7%BC%93%E5%AD%98%E4%B8%80%E8%87%B4%E6%80%A7%E4%B8%8E%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B%E7%9A%84%E5%85%B3%E7%B3%BB</link>
    <guid>https://garden.linusboyle.cn/idea/20260821024532-%E7%BC%93%E5%AD%98%E4%B8%80%E8%87%B4%E6%80%A7%E4%B8%8E%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B%E7%9A%84%E5%85%B3%E7%B3%BB</guid>
    <description><![CDATA[ &lt;p&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;a href=&quot;../idea/memory-consistency-model&quot; class=&quot;internal alias&quot; data-slug=&quot;idea/memory-consistency-model&quot;&gt;memory consistency model&lt;/a&gt;之间的关系，可以分为两大类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consistency-agnostic coherence：此类缓存一致性是同步实现的，此时，缓存仿佛在&lt;a href=&quot;../idea/20260821025035-Memory-Hierarchy&quot; class=&quot;internal alias&quot; data-slug=&quot;idea/20260821025035-Memory-Hierarchy&quot;&gt;内存层级&lt;/a&gt;中不存在，对程序和程序员完全透明，内存系统可以被当作是原子的。在此类情况下，&lt;a href=&quot;../idea/memory-consistency-model&quot; class=&quot;internal alias&quot; data-slug=&quot;idea/memory-consistency-model&quot;&gt;memory consistency model&lt;/a&gt;通过处理器的微架构实现。&lt;/li&gt;
&lt;li&gt;Consistency-directed coherence：缓存一致性是异步实现的，因此可能会出现过时的数据被读取的情况。此时，缓存一致性协议和处理器一同实现内存模型。这种协议主要出现在异构系统中，如GPU。（&lt;a href=&quot;../idea/Sequential-Consistency&quot; class=&quot;internal alias&quot; data-slug=&quot;idea/Sequential-Consistency&quot;&gt;SC&lt;/a&gt;和&lt;a href=&quot;../idea/Total-Store-Order&quot; class=&quot;internal alias&quot; data-slug=&quot;idea/Total-Store-Order&quot;&gt;TSO&lt;/a&gt;都可以实现）&lt;/li&gt;
&lt;/ul&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;a href=&quot;../source/Zotero/nagarajanPrimerMemoryConsistency2020&quot; class=&quot;internal alias&quot; data-slug=&quot;source/Zotero/nagarajanPrimerMemoryConsistency2020&quot;&gt;A Primer on Memory Consistency and Cache Coherence&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&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;/li&gt;
&lt;/ul&gt; ]]></description>
    <pubDate>Fri, 21 Aug 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>Memory Hierarchy</title>
    <link>https://garden.linusboyle.cn/idea/20260821025035-Memory-Hierarchy</link>
    <guid>https://garden.linusboyle.cn/idea/20260821025035-Memory-Hierarchy</guid>
    <description><![CDATA[ &lt;blockquote&gt;
&lt;p&gt;理想情况下,我们希望拥有无限大的存储容量,这样就可以立刻访问任何一个特定的机器字…但我们 … 必须认识到构建一个存储器层次结构的可能性,其中每一层次的容量都比前一层次大,但访问速度却比前一层次慢。 A. W. Burks、H. H. Goldstine 及 J. von Neumann,  Preliminary Discussion of the Logical Design of an Electronic Computing Instrument ( 1946 )&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;利用局部性原理设计的存储器结构。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“In most cases (but not all) the data contained in a lower level are a superset of the next higher level. This property, called the inclusion property, is usually maintained by the main memory in the case of caches and by secondary storage (disk or Flash) in the case of virtual memory.”&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;“Virtually all computers since 1975 have used DRAMs for main memory and SRAMs for cache, with one to three levels integrated onto the processor chip with the CPU. Today, all PMDs and laptops and most desktops use Flash rather than disk drives. Many servers use Flash in combination with disk drives.”&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;/li&gt;
&lt;/ul&gt; ]]></description>
    <pubDate>Fri, 21 Aug 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>Computer Architecture: A Quantitative Approach</title>
    <link>https://garden.linusboyle.cn/source/Zotero/hennessyComputerArchitectureQuantitative2026</link>
    <guid>https://garden.linusboyle.cn/source/Zotero/hennessyComputerArchitectureQuantitative2026</guid>
    <description><![CDATA[ &lt;h2 id=&quot;computer-architecture-a-quantitative-approach&quot;&gt;&lt;a href=&quot;zotero://select/library/items/H6HACKJ4&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Computer Architecture: A Quantitative Approach&lt;/a&gt;&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#computer-architecture-a-quantitative-approach&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 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;John L. Hennessy, David A. Patterson, and Christos Kozyrakis. 2026. &lt;em&gt;Computer Architecture: A Quantitative Approach&lt;/em&gt; (7th ed.). Morgan Kaufmann Publischers an imprint of Elsevier, San Francisco.&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/7658M6VQ&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;PDF&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;a href=&quot;zotero://select/library/collections/VKTA5EBV&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;A 计算机科学/1 系统结构&lt;/a&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;The late 1970s saw the emergence of the microprocessor.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;two significant changes in the computer marketplace made it easier than ever to succeed commercially with a new architecture. First, the virtual elimination of assembly language programming reduced the need for object-code compatibility. Second, the creation of standardized, vendor-independent operating systems, such as UNIX and its clone, Linux, lowered the cost and risk of bringing out a new architecture.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Intel rose to the challenge, primarily by translating 80x86 instructions into RISC-like instructions internally, allowing it to adopt many of the innovations first pioneered in the RISC designs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;In 1974, Robert Dennard observed that power density was constant for a given area of silicon even as you increased the number of transistors because of smaller dimensions of each transistor.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;This change forced the microprocessor industry to use multiple efficient processors or cores instead of a single inefficient processor.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Whereas the compiler and hardware conspire to exploit ILP implicitly without the programmer’s attention, DLP, TLP, and RLP are explicitly parallel, requiring the restructuring of the application so that it can exploit explicit parallelism. In some instances this is easy; in many it is a major new burden for programmers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The only path left to improve energy-performance-cost significantly is specialization. Future microprocessors will include several domain-specific cores that perform only one class of computations well, but they do so remarkably better than general-purpose cores.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;ome are investigating alternatives that have not yet had significant commercial impact, e.g., analog, biological, quantum, neuromorphic, or asynchronous computing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Although the range of computing power in the embedded computing market is very large, price is a key factor in the design of computers for this space. Performance requirements do exist, of course, but the primary goal often meets the performance need at a minimum price rather than achieving more performance at a higher price.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Energy and size requirements lead to the use of Flash memory for storage (Chapter 2) instead of magnetic disks.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;We use the ability to run third-party software as the dividing line between nonembedded and embedded computers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;the cost target for servers is total cost of ownership (TCO) rather than purchase price. TCO is the purchase price plus the cost of operation over the lifetime of the computer, which includes the cost of electricity, cooling, maintenance, and space.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;the purchase price of the server processor can be a quarter of the total TCO.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Clusters are collections of typically inexpensive servers connected by local area networks to act as a single larger computer. Each node runs its own operating system, and nodes communicate using a networking protocol.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Single instruction stream, single data stream (SISD)dThis category is the uniprocessor. The programmer thinks of it as the standard sequential computer, but it can exploit ILP.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Single instruction stream, multiple data streams (SIMD)dThe same instruction  is executed by multiple processors using different data streams.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;In the early SIMD computers each processor had its own data memory (hence the MD of SIMD), but there is a single instruction memory and control processor, which fetches and dispatches instructions. (Recent SIMD computers fetch multiple data items at a time from a single shared memory.)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Multiple instruction streams, single data stream (MISD)dNo successful commercial multiprocessor of this type has been built to date, but it rounds out this simple classification&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Multiple instruction streams, multiple data streams (MIMD)dEach processor  fetches its own instructions and operates on its own data,&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The architect’s or designer’s job is much more than instruction set design, and the technical hurdles in the other aspects of the project are likely more challenging than those encountered in instruction set design.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;There are two basic choices for encoding: fixed length and variable length.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;All ARMv8 and RISC-V instructions are 32 bits long, which simplifies instruction decoding.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The x86 encoding is variable length, 1 to 18 bytes. Variable-length instructions can take less space than fixed-length instructions, so a program compiled for the x86 is usually smaller than the same program compiled for RISC-V.&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>Fri, 21 Aug 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>ISA</title>
    <link>https://garden.linusboyle.cn/idea/20260820040857-ISA</link>
    <guid>https://garden.linusboyle.cn/idea/20260820040857-ISA</guid>
    <description><![CDATA[ &lt;p&gt;软件与硬件之间的分野，可见于开发者的编程界面&lt;/p&gt;
&lt;h2 id=&quot;classification&quot;&gt;Classification&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#classification&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;ul&gt;
&lt;li&gt;&lt;strong&gt;register-memory ISA&lt;/strong&gt;, such as the x86: access memory as part of many instructions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;load-store ISA&lt;/strong&gt;, such as ARMv8 and RISC-V:  access memory only  with load or store instructions. All ISAs announced since 1985 are load-store.&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;几乎所有ISA（包括x86、ARMv8和RISC-V）都使用字节寻址来访问内存操作数。某些架构（如ARMv8）要求对象必须&lt;strong&gt;对齐&lt;/strong&gt;。x86 和 RISC-V 不要求对齐，但如果操作数对齐，访问通常更快。&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;p&gt;编码有两种基本选择：固定长度和可变长度。x86 采用可变长度编码，RISC-V 和 ARM 为固定长度。&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;../source/annotation/x86x64-CPU-architecture-the-stack--and--stack-frames&quot; class=&quot;internal alias&quot; data-slug=&quot;source/annotation/x86x64-CPU-architecture-the-stack--and--stack-frames&quot;&gt;x86x64 CPU architecture the stack &amp;#x26; stack frames&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;../source/Zotero/hennessyComputerArchitectureQuantitative2026&quot; class=&quot;internal&quot; data-slug=&quot;source/Zotero/hennessyComputerArchitectureQuantitative2026&quot;&gt;hennessyComputerArchitectureQuantitative2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt; ]]></description>
    <pubDate>Thu, 20 Aug 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>The History of FORTRAN</title>
    <link>https://garden.linusboyle.cn/source/clipped/The-History-of-FORTRAN</link>
    <guid>https://garden.linusboyle.cn/source/clipped/The-History-of-FORTRAN</guid>
    <description><![CDATA[ &lt;p&gt;FORTRAN was the world’s first high-level programming language. It was developed at IBM by a small team led by John Backus. The earliest version of FORTRAN was released in 1957 as a programming tool for the IBM 704. Fifty years later, FORTRAN remains the programming language of choice for large-scale numerical calculations in science and engineering.&lt;/p&gt;
&lt;h2 id=&quot;before-fortran&quot;&gt;Before FORTRAN&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#before-fortran&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;Programs for the earliest computers consisted of sequences of numerical codes. Each code represented a basic operation such as ‘fetch a number from memory location X and put it in register A’ or ‘add the number in register A to the number in register B’. This style of programming was time-consuming and error-prone. Mistakes were difficult to find.&lt;/p&gt;
&lt;p&gt;By the time John Backus joined IBM as a scientific programmer in 1950, it had become possible to write programs using mnemomics such as &lt;em&gt;ADD&lt;/em&gt; in place of the numerical codes. A special program (which we would call an assembler today) converted the mnemonics into the corresponding numerical codes. This made programming a little easier, but even a simple program required dozens of operations, and it was still difficult to track down mistakes.&lt;/p&gt;
&lt;p&gt;Backus reasoned that it should be possible to create a programming language which allowed a series of calculations to be expressed in something resembling mathematical notation. A translation program (a compiler, in today’s terminology) would then convert it into the numerical codes which the computer understood. Backus proposed this idea to his manager in 1953. He was given a budget and encouraged to hire a small team to test the feasibility of the notion.&lt;/p&gt;
&lt;p&gt;Three years later, the team published a manual which described the IBM Mathematical Formula Translating System, or FORTRAN for short. Soon after, IBM made the first FORTRAN compiler available to users of the IBM 704.&lt;/p&gt;
&lt;p&gt;Backus and his team had created the world’d first high-level programming language. Scientists and engineers would no longer have to write their programs as numerical codes or long-winded mnemonics.&lt;/p&gt;
&lt;p&gt;Significantly, Backus’s team had implemented the first &lt;strong&gt;optimizing&lt;/strong&gt; compiler, which not only translated FORTRAN programs into the IBM 704’s numerical codes, but produced codes which ran very nearly as fast as anything that could be crafted by hand.&lt;/p&gt;
&lt;p&gt;This was very important in ensuring the success of FORTRAN. Early computers were very slow by today’s standards, and they represented an expensive commodity to their owners. Inefficient programs wasted time and money. Backus and his team understood this, and they knew that they had to confound their critics who said that a program compiled from a high-level language could never be as efficient as one that was hand-crafted directly using numerical codes or mnemonics.&lt;/p&gt;
&lt;h2 id=&quot;the-early-years&quot;&gt;The Early Years&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#the-early-years&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 1958, IBM released a revised version of the language, named FORTRAN II. It provided support for procedural programming by introducing statements which allowed programmers to create subroutines and functions, thereby encouraging the re-use of code.&lt;/p&gt;
&lt;p&gt;FORTRAN’s growing popularity led many computer manufacturers to implement versions of it for their own machines. Each manufacturer added its own customisations, making it impossible to guarantee that a program written for one type of machine would compile and run on a different type. IBM responded by removing all machine-dependent features from its version of the language. The result, released in 1961, was called FORTRAN IV.&lt;/p&gt;
&lt;h2 id=&quot;fortran-66&quot;&gt;FORTRAN 66&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#fortran-66&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;By the early 1960s, there was growing pressure to create a standardised version of FORTRAN which was not tied to any single type of computer. In 1962, the &lt;strong&gt;American Standards Association&lt;/strong&gt; (the precursor of ANSI, the &lt;strong&gt;American National Standards Institute&lt;/strong&gt;) convened a committee to pursue this goal. The result, published in 1966, was a document which defined the language which became known as FORTRAN 66.&lt;/p&gt;
&lt;p&gt;FORTRAN 66 marked a significant milestone in computer science. It was the first programming language to be defined by a formal standard.&lt;/p&gt;
&lt;h2 id=&quot;fortran-77&quot;&gt;FORTRAN 77&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#fortran-77&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;Within only a few years, the shortcomings of FORTRAN 66 began to become apparent, especially by comparison with other programming languages such as C, Pascal and Algol. Computer manufacturers again added customisations to the language to try to address some of these faults.&lt;/p&gt;
&lt;p&gt;This forced the ANSI FORTRAN standards committee, known as X3J3, to start work on a new version of the language in 1969. The resulting standard would take eight years to reach maturity, but the language it defined, known as FORTRAN 77, represented a major enhancement. Among the features which it added were a true block &lt;code&gt;IF&lt;/code&gt; statement, a &lt;code&gt;CHARACTER&lt;/code&gt; data type, direct-access I/O and the &lt;code&gt;PARAMETER&lt;/code&gt; statement to define constants.&lt;/p&gt;
&lt;p&gt;FORTRAN 77 became the became the most widely-used version of the language, and it is likely that much of the legacy FORTRAN code around the world is written in this dialect of the language.&lt;/p&gt;
&lt;h2 id=&quot;fortran-90&quot;&gt;FORTRAN 90&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#fortran-90&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;FORTRAN 77 faced competition from languages such as C, which allowed programmers to allocate memory dynamically and to define heterogeneous data structures. FORTRAN 77 could do neither of these things. The next version of FORTRAN to emerge from the ANSI X3J3 committee was designed to address these deficiencies. It was tentatively named FORTRAN 8X but by the late 1980s, the committee did not appear to be close to releasing the new standard, and there was a popular joke among computer scientists that ‘X’ would need to be a hexadecimal digit.&lt;/p&gt;
&lt;p&gt;The new version of FORTRAN was finally published as a standard by the &lt;strong&gt;International Standards Organisation&lt;/strong&gt; in 1991, and it became known informally as FORTRAN 90.&lt;/p&gt; ]]></description>
    <pubDate>Sun, 16 Aug 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>奥德赛</title>
    <link>https://garden.linusboyle.cn/source/video/%E5%A5%A5%E5%BE%B7%E8%B5%9B</link>
    <guid>https://garden.linusboyle.cn/source/video/%E5%A5%A5%E5%BE%B7%E8%B5%9B</guid>
    <description><![CDATA[ &lt;p&gt;诺兰导演，改编自希腊史诗。叙事结构相比原著有调整，也改了一些设定。&lt;/p&gt;
&lt;p&gt;不讨论古典学和场外争议，其实是不错的电影。最直接想表达的意涵显然是反战的，奥德修斯颇有一种战后PTSD老兵的形象。&lt;/p&gt; ]]></description>
    <pubDate>Fri, 14 Aug 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>Logical Foundations of Example-Driven Specification</title>
    <link>https://garden.linusboyle.cn/idea/Logical-Foundations-of-Example-Driven-Specification</link>
    <guid>https://garden.linusboyle.cn/idea/Logical-Foundations-of-Example-Driven-Specification</guid>
    <description><![CDATA[ &lt;p&gt;Conjunctive Queries and LTL&lt;/p&gt;
&lt;p&gt;Balder ten Cate&lt;/p&gt;
&lt;h2 id=&quot;database-query&quot;&gt;Database Query&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#database-query&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;Fitting problem: given a set of labeled samples, construct a conjunctive query&lt;/p&gt;
&lt;p&gt;sample: the answer tuple&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;conjunctive query&lt;/strong&gt;: FOL using only existential quantifier and conjunction; Capture the select-project-join queries in SQL&lt;/p&gt;
&lt;h3 id=&quot;most-specific-fitting-cq&quot;&gt;Most-specific fitting CQ&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#most-specific-fitting-cq&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;所有满足约束的CQ（对子集关系）组成凸集。如果满足约束的CQ存在，则一定有极点。（PODS23）&lt;/p&gt;
&lt;h3 id=&quot;query-repair&quot;&gt;Query Repair&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#query-repair&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;Given an existing query that does not hold, find the ‘closest’ that fits the constraints.&lt;/p&gt;
&lt;p&gt;different interpretation of ‘closeness’&lt;/p&gt;
&lt;h2 id=&quot;ltl&quot;&gt;&lt;a href=&quot;../idea/LTL&quot; class=&quot;internal&quot; data-slug=&quot;idea/LTL&quot;&gt;LTL&lt;/a&gt;&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#ltl&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;Generate a ‘good’ set of examples for a given LTL formula.&lt;/p&gt;
&lt;p&gt;Full LTL can’t be uniquely characterized by finite examples&lt;/p&gt;
&lt;p&gt;Fragment: LTL with future and no negation&lt;/p&gt;
&lt;p&gt;Every formula in this fragment can be uniquely represented by a finite set of &lt;strong&gt;transfinite&lt;/strong&gt; traces, or a finite set of labeled schematic examples.&lt;/p&gt;
&lt;p&gt;schematic examples: union-free regular expression over B(AP),  the Boolean combination of some atomic propositions.&lt;/p&gt;
&lt;p&gt;The proof is straightforward : for finite traces, LTL language is regular, which is equivalent to a union of the language of a union-free regular expression.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Theory and applications of Craig Interpolation&lt;/p&gt; ]]></description>
    <pubDate>Fri, 22 May 2026 00:00:00 GMT</pubDate>
  </item><item>
    <title>Making a Splash</title>
    <link>https://garden.linusboyle.cn/source/clipped/Making-a-Splash</link>
    <guid>https://garden.linusboyle.cn/source/clipped/Making-a-Splash</guid>
    <description><![CDATA[ &lt;p&gt;To splash, or not to splash in your Draft deck? That is the question.&lt;/p&gt;
&lt;p&gt;This is a question that can topple 40-card empires, cause massive deck-building consternation, and be the thin line between victory and defeat.&lt;/p&gt;
&lt;p&gt;I’ve reaped the benefits of splashing many times. I’ve also definitely splashed when I shouldn’t have, and errantly left a splash out when I should have put it in. I’d guess that, at some point or another, the same may have been true for you, loyal reader.&lt;/p&gt;
&lt;p&gt;Splashing is always so tempting—and it’s important to know when to go for it or have enough discipline to stay the course.&lt;/p&gt;
&lt;p&gt;So then, shall we take a look at the art of the splash today?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://media.wizards.com/2017/images/daily/c4rd4r7_4V2ztLZBeH.jpg&quot; alt=&quot;Bounty of the Luxa&quot; loading=&quot;lazy&quot;&gt;&lt;/p&gt;
&lt;p&gt;Bounty of the Luxa | Art by Jonas De Ro&lt;/p&gt;
&lt;p&gt;Okay, first, I think it’s important to clarify what exactly a “splash” &lt;em&gt;is&lt;/em&gt; when it comes to Limited gameplay.&lt;/p&gt;
&lt;p&gt;It’s simple: a splash is when you’re touching just a smidge of a color to play a couple cards of that color. Generally, I’d say it’s something like you’re playing just one to three cards of that color. Usually, in a Limited deck, you’ll be two colors, and when you splash, you splash your third. There are exceptions, sure—I’ve played my fair amount of four- or five-color crazy splashes—but that’s a good way to think about it.&lt;/p&gt;
&lt;p&gt;So, for example, you might have drafted green-blue, splashing red for some removal spells. Maybe your deck is something like 21 green and blue cards and two red cards. That’s a splash.&lt;/p&gt;
&lt;p&gt;If it was something more like eight green cards, eight blue cards, and six red cards, then I’d be more inclined to say you’re a three-color deck and less of a splash. Generally, splashes are just for a couple cards. This is partially an issue of nomenclature, but it will also help make sure we’re on the same page the whole way through.&lt;/p&gt;
&lt;p&gt;As a rule of thumb, I recommend playing about three sources of a given color if I’m going to splash it. This can go up and down depending on the cards you’re splashing. Sometimes it can be two if you’re just splashing one card or you really need the colored mana elsewhere. But three is a good place to start.&lt;/p&gt;
&lt;p&gt;So, if I was splashing two red cards, to be safe, I’d try and play at least three Mountains, two Mountains and an&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?name=Evolving+Wilds&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Evolving Wilds&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;, or any combination of cards that gets me to three ways to find my red mana in a pinch. (And generally, I am reticent to splash in the first place without any sort of color fixing.)&lt;/p&gt;
&lt;p&gt;Okay. So, now that we’ve established what a splash is, when should you do it? Why would you want to do it?&lt;/p&gt;
&lt;p&gt;Let’s cover five dos and don’ts when it comes to splashing.&lt;/p&gt;
&lt;h2 id=&quot;1-do-not-splash-cards-you-want-to-cast-early&quot;&gt;1. Do Not Splash Cards You Want to Cast Early&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#1-do-not-splash-cards-you-want-to-cast-early&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;Generally, you’re going to be casting any given splash card later in the game rather than earlier. If you’re only playing three Mountains for your red splash, then you not only have to draw the card you want to cast, but you also have to draw a Mountain to help you cast it in the first place!&lt;/p&gt;
&lt;p&gt;Some cards fall into poor categories for splashing. For example, creatures you want to cast in the early game are poor choices to splash. By the time you can cast them, the game will likely be in a spot where splashing them wasn’t worth it. Splashing mana fixing or acceleration is an easy trap to fall into when trying to build a three-color deck, but putting the fixing or acceleration into the color you need to fix for in the first place doesn’t actually help you out much!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?name=Glory-Bound+Initiate&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://gatherer.wizards.com/Handlers/Image.ashx?type=card&amp;#x26;name=Glory-Bound+Initiate&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?name=Channeler+Initiate&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://gatherer.wizards.com/Handlers/Image.ashx?type=card&amp;#x26;name=Channeler+Initiate&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This isn’t to say that you don’t want to splash cards that are cheap to cast. There can be cheap cards that will still have a large impact. But often this means more along the lines of spells, such as removal, which can be excellent to splash. Something like&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?name=Glory-Bound+Initiate&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Glory-Bound Initiate&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;, however, loses a bit of its luster on turn ten.&lt;/p&gt;
&lt;p&gt;And speaking of splashing removal…&lt;/p&gt;
&lt;h2 id=&quot;2-do-splash-what-covers-your-weaknesses-and-adds-power&quot;&gt;2. Do Splash What Covers Your Weaknesses and Adds Power&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#2-do-splash-what-covers-your-weaknesses-and-adds-power&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 main goal of a splash should be to cover your deck’s weaknesses. (Heeding the first point in mind, of course; you shouldn’t generally go splashing cheap creatures even if early plays are your weakness.)&lt;/p&gt;
&lt;p&gt;Most of the time, I would say that this boils down to removal or incredibly powerful “bomb” cards.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?name=Trial+of+Ambition&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://gatherer.wizards.com/Handlers/Image.ashx?type=card&amp;#x26;name=Trial+of+Ambition&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?name=Deem+Worthy&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://gatherer.wizards.com/Handlers/Image.ashx?type=card&amp;#x26;name=Deem+Worthy&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Removal spells are key to Limited gameplay. Your ability to kill off your opponent’s creatures and nullify some of their strongest cards is going to be a big factor in most decks’ ability to win or lose.&lt;/p&gt;
&lt;p&gt;Splashing removal is also a pretty safe bet. When it comes to cards that are good in the long game (which is where your splashes generally come online), removal spells are great to have around. They’re excellent in any kind of attrition battle and help ensure you have the last creature standing.&lt;/p&gt;
&lt;p&gt;While not truly a “weakness,” your deck can always use more powerful bomb rares or uncommons you may have opened. Splashing powerful cards can be worth it if the impact of the card is high enough and you have the means to do it.&lt;/p&gt;
&lt;p&gt;Finally, another kind of card I tend to splash sometimes are big creatures. Sometimes, I’ll be playing a slower deck that just needs a way to win. It doesn’t need to be the most efficient way to win—but an extra copy of an expensive flier or huge ground creature can be a good way to close out the game.&lt;/p&gt;
&lt;p&gt;Think about what your deck needs and see if your splashes can help cover it.&lt;/p&gt;
&lt;h2 id=&quot;3-do-not-ignore-colored-mana-requirements&quot;&gt;3. Do Not Ignore Colored Mana Requirements&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#3-do-not-ignore-colored-mana-requirements&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;So you have a&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?name=Glorybringer&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Glorybringer&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;, right? Big awesome Dragon, super powerful rare. You definitely want to splash that, right?&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?name=Glorybringer&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://gatherer.wizards.com/Handlers/Image.ashx?type=card&amp;#x26;name=Glorybringer&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Not so fast.&lt;/p&gt;
&lt;p&gt;It can be so tempting to try to get that powerful rare in there. However, there is a limit to the strain you can put on your mana base to try and accommodate for something. And generally, if you want to splash something that has two off-color mana symbols (such as 3RR if you’re playing green-blue) in its mana cost, you’re crossing the line.&lt;/p&gt;
&lt;p&gt;There is a tremendous difference between having to find one of a certain color and having to find a second of that color. And unless your deck is really well equipped on mana fixing, this is a splash most often left on the sidelines.&lt;/p&gt;
&lt;p&gt;Let’s say you’re playing three red sources as your baseline to cast&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?name=Glorybringer&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Glorybringer&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;. You will need to draw two of them plus[&lt;/p&gt;
&lt;p&gt;Glorybringer&lt;/p&gt;
&lt;p&gt;](&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?name=Glorybringer)over&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;https://gatherer.wizards.com/Pages/Card/Details.aspx?name=Glorybringer)over&lt;/a&gt; the course of the game to make it relevant. And you &lt;em&gt;could&lt;/em&gt; add more sources, but it’s important to keep in mind that the cost is much larger than just “Can I cast this[&lt;/p&gt;
&lt;p&gt;Glorybringer&lt;/p&gt;
&lt;p&gt;](&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?name=Glorybringer)or&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;https://gatherer.wizards.com/Pages/Card/Details.aspx?name=Glorybringer)or&lt;/a&gt; not?”—you are also impacting your mana base on the whole. What about the games where you draw a Mountain instead of the Island you need to cast most of the cards in your deck? Those are the ways splashing can start to crunch you.&lt;/p&gt;
&lt;p&gt;If you’re already splashing red, you could &lt;em&gt;maybe&lt;/em&gt; start to think about finding a way to fit that&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?name=Glorybringer&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Glorybringer&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;in. But splashing just for it is likely to make your deck weaker on the whole, thanks to your destabilizing mana base.&lt;/p&gt;
&lt;p&gt;Now, &lt;em&gt;Amonkhet&lt;/em&gt; is a little different than normal in this respect because it does contain a way to pitch away your extra cards: cycling!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?name=Archfiend+of+Ifnir&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://gatherer.wizards.com/Handlers/Image.ashx?type=card&amp;#x26;name=Archfiend+of+Ifnir&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Archfiend makes a much better splash. If you ever get to the two black mana needed to cast it, that’s great—but it’s also not going to rot away in your hand since you can always cycle it. I’d be happy to play the Archfiend in my black-splash deck, whereas I’d be a lot more skeptical about the&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?name=Glorybringer&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Glorybringer&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;in a deck with a red splash.&lt;/p&gt;
&lt;p&gt;But even then, I wouldn’t splash &lt;em&gt;just&lt;/em&gt; for the Archfiend. If I was already playing some black sources for removal and had access to the Archfiend, sure. But splashing just for a double-colored card is something I’d advise against.&lt;/p&gt;
&lt;h2 id=&quot;4-do-think-about-your-splashes-during-the-draft&quot;&gt;4. Do Think About your Splashes During the Draft&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#4-do-think-about-your-splashes-during-the-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;/h2&gt;
&lt;p&gt;If you get to the deck building portion of your draft and you’re not sure if you can splash or not, then it might already be too late.&lt;/p&gt;
&lt;p&gt;To try to make your splashes work, you really want to be actively thinking about them during the draft. If I picked a powerful rare, but I moved out of the colors to play it, I’ll keep my eyes open for anything that may help me put it into my deck. For example, a dual land such as&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?name=Sheltered+Thicket&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Sheltered Thicket&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;could help make the red splash in my green-blue deck happen. Prioritizing[&lt;/p&gt;
&lt;p&gt;Spring // Mind&lt;/p&gt;
&lt;p&gt;](&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?name=Spring+%2F%2F+Mind)a&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;https://gatherer.wizards.com/Pages/Card/Details.aspx?name=Spring+%2F%2F+Mind)a&lt;/a&gt; little bit higher can be the difference between splashing or not.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?name=Sheltered+Thicket&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://gatherer.wizards.com/Handlers/Image.ashx?type=card&amp;#x26;name=Sheltered+Thicket&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gatherer.wizards.com/Pages/Card/Details.aspx?name=Spring+%2F%2F+Mind&quot; class=&quot;external&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://gatherer.wizards.com/Handlers/Image.ashx?type=card&amp;#x26;name=Spring+%2F%2F+Mind&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;While maybe there’s another, stronger card in the pack than the mana fixing, if taking the fixing lets you play a couple awesome splash cards, then what you’re really comparing is those awesome splash cards to the other card you could take here. And that’s when you have to ask yourself: which would you choose?&lt;/p&gt;
&lt;h2 id=&quot;5-do-not-splash-in-decks-that-dont-want-splashes&quot;&gt;5. Do Not Splash in Decks That Don’t Want Splashes&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#5-do-not-splash-in-decks-that-dont-want-splashes&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;Finally, think about your deck. Does it want that splash? Does it need that splash? Can it make use of that splash?&lt;/p&gt;
&lt;p&gt;A typical example of something I’d warn against is splashing in an aggressive deck. Splashes are best if the game goes long, so unless you have something incredibly powerful or access to very good mana fixing, I generally would lean against splashing in your aggressive Limited deck. Plus, destabilizing your mana can be especially brutal to aggressive decks, since you need to hit your creatures on curve.&lt;/p&gt;
&lt;p&gt;But it goes further than that. Sometimes, your deck is just in good shape without that splash you’re considering. If you’re taking out two good cards of another color to make room for two slightly better cards in a splash, you may just be hurting your mana base more than you’re actually helping your deck.&lt;/p&gt;
&lt;p&gt;If I’m thinking about splashing at the end of the draft, I’ll always build two versions of my deck: one with the splash, and one without it. Then, compare them. How strong is the splash? Does your deck need the help? Looking at both versions side by side can help answer this question.&lt;/p&gt;
&lt;p&gt;And keep in mind, you can always sideboard in and out of a splash! If you’re playing against a quick beatdown deck and don’t have the time to worry about mana problems, sideboard it out. If your game is going to go long and you want more strong threats, bring it in. Sideboarding in Limited is generally underused and a great place to help adjust your splash to match what your opponent is throwing at you.&lt;/p&gt;
&lt;h2 id=&quot;splash-attack&quot;&gt;Splash Attack&lt;a role=&quot;anchor&quot; aria-hidden tabindex=&quot;-1&quot; data-no-popover href=&quot;#splash-attack&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 good splash can let you play cards when you otherwise never would have. A bad one can cost you the draft. Hopefully, armed with this information, you can go out and make more informed splashing decisions.&lt;/p&gt;
&lt;p&gt;When in doubt, I generally recommend not splashing. I’ve seen plenty of drafts derailed by mana destabilization of a splash a player was on the edge about. If your deck works fine without it, you can usually consider leaving it in the board.&lt;/p&gt;
&lt;p&gt;On the other hand, if your mana base is really good with multiple pieces of mana fixing and the splash is nearly free, then I’d be a lot more willing to go for it. In the end, look at your deck and see what looks right for this particular draft.&lt;/p&gt;
&lt;p&gt;And where to test this all out? Well, you’re just in time to go draft some &lt;em&gt;Amonkhet&lt;/em&gt;! With plenty of opportunities to &lt;a href=&quot;http://magic.wizards.com/en/event-types/draft-weekend&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;draft this week&lt;/a&gt;, now is a good time to put this into practice. Go forth and splash!&lt;/p&gt;
&lt;p&gt;Do you have any thoughts or feedback? I’d love to hear from you! Reaching me is easy: you can always find me on my &lt;a href=&quot;http://www.twitter.com/gavinverhey&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Twitter&lt;/a&gt;, &lt;a href=&quot;http://www.gavinverhey.tumblr.com/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;Tumblr&lt;/a&gt;, or, alternatively, by sending me an e-mail (in English, please) at &lt;a href=&quot;mailto:BeyondBasicsMagic@gmail.com&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;BeyondBasicsMagic@gmail.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I’ll be back next week with more Beyond the Basics. Enjoy drafting this week, and I’ll talk with you again then!&lt;/p&gt;
&lt;p&gt;Gavin&lt;br&gt;
&lt;a href=&quot;http://www.twitter.com/gavinverhey&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;@GavinVerhey&lt;/a&gt;&lt;br&gt;
&lt;a href=&quot;http://www.gavinverhey.tumblr.com/&quot; class=&quot;external alias&quot; target=&quot;_blank&quot;&gt;GavInsight&lt;/a&gt;&lt;/p&gt; ]]></description>
    <pubDate>Tue, 12 May 2026 00:00:00 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>
    </channel>
  </rss>