<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
  <title>jordi.inversethought.com</title>
  <link>https://aggr.aymericbeaumet.com/sources/jordi.inversethought.com/</link>
  <description>Browse aymeric&#39;s, an independent, searchable archive of readable snapshots from followed feeds, preserved in Git with aggr.</description>
  <language>en</language>
  <atom:link href="https://aggr.aymericbeaumet.com/sources/jordi.inversethought.com/rss.xml" rel="self" type="application/rss+xml"/>
  <lastBuildDate>Sat, 31 Oct 2026 15:05:04 +0000</lastBuildDate>
  <generator>aggr</generator>
  <item>
    <title>The Kluever Maneuver</title>
    <link>https://aggr.aymericbeaumet.com/items/lobste-rs/2026-10-31-the-kluever-maneuver/</link>
    <guid isPermaLink="false">urn:aggr:item:3a1df9c2ee2c8a0bfa09bed4fe1c6ee5207ef263</guid>
    <atom:link href="https://jordi.inversethought.com/blog/the-kluever-maneuver/" rel="via" type="text/html"/>
    <pubDate>Sat, 31 Oct 2026 15:05:04 +0000</pubDate>
    <dc:creator>jordi.inversethought.com by JordiGH</dc:creator>
    <description>Comments</description>
    <content:encoded>&lt;p&gt;In brief, it’s this: whenever you are doing a bugfix, do it in two commits.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Write a passing test that exemplifies the buggy behaviour.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fix the bug and also fix the test we just wrote.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For example,&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Python&quot;&gt;&lt;span class=&quot;syntax-source syntax-python&quot;&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-python&quot;&gt;&lt;span class=&quot;syntax-storage syntax-type syntax-function syntax-python&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;syntax-entity syntax-name syntax-function syntax-python&quot;&gt;&lt;span class=&quot;syntax-meta syntax-generic-name syntax-python&quot;&gt;add&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-parameters syntax-python&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parameters syntax-begin syntax-python&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-parameters syntax-python&quot;&gt;&lt;span class=&quot;syntax-variable syntax-parameter syntax-python&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-separator syntax-parameters syntax-python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;syntax-variable syntax-parameter syntax-python&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parameters syntax-end syntax-python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-python&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-function syntax-begin syntax-python&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
   &lt;span class=&quot;syntax-keyword syntax-control syntax-flow syntax-return syntax-python&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-qualified-name syntax-python&quot;&gt;&lt;span class=&quot;syntax-meta syntax-generic-name syntax-python&quot;&gt;a&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-operator syntax-arithmetic syntax-python&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-qualified-name syntax-python&quot;&gt;&lt;span class=&quot;syntax-meta syntax-generic-name syntax-python&quot;&gt;b&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-operator syntax-arithmetic syntax-python&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python&quot;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and through your keen eye you observe that this addition function is buggy. You therefore write a test that records the bad behaviour,&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Diff&quot;&gt;&lt;span class=&quot;syntax-source syntax-diff&quot;&gt;Commit 1

diff --git a/test_arith.py b/test_arith.py
&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-from-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-from-file syntax-diff&quot;&gt;---&lt;/span&gt; a/test_arith.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-to-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-to-file syntax-diff&quot;&gt;+++&lt;/span&gt; b/test_arith.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-range syntax-unified&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-toc-list syntax-line-number syntax-diff&quot;&gt;-0,0 +1,2&lt;/span&gt; &lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;def test_add(a, b):
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;   assert add(2, 2) == 5
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then comes the bugfix,&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Diff&quot;&gt;&lt;span class=&quot;syntax-source syntax-diff&quot;&gt;Commit 2

diff --git a/arith.py b/arith.py
&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-from-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-from-file syntax-diff&quot;&gt;---&lt;/span&gt; a/arith.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-to-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-to-file syntax-diff&quot;&gt;+++&lt;/span&gt; b/arith.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-range syntax-unified&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-toc-list syntax-line-number syntax-diff&quot;&gt;-1,2 +1,2&lt;/span&gt; &lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt;
&lt;/span&gt; def add(a, b):
&lt;span class=&quot;syntax-markup syntax-deleted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-deleted syntax-diff&quot;&gt;-&lt;/span&gt;   return a + b + 1
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;   return a + b
&lt;/span&gt;diff --git a/test_arith.py b/test_arith.py
&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-from-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-from-file syntax-diff&quot;&gt;---&lt;/span&gt; a/test_arith.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-to-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-to-file syntax-diff&quot;&gt;+++&lt;/span&gt; b/test_arith.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-range syntax-unified&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-toc-list syntax-line-number syntax-diff&quot;&gt;-1,2 +1,2&lt;/span&gt; &lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt;
&lt;/span&gt; def test_add(a, b):
&lt;span class=&quot;syntax-markup syntax-deleted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-deleted syntax-diff&quot;&gt;-&lt;/span&gt;   assert add(2, 2) == 5
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;   assert add(2, 2) == 4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;BUT Y THO&lt;/h2&gt;
&lt;p&gt;Three reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Clearly shows exactly how the bug currently behaves&lt;/li&gt;
&lt;li&gt;Demonstrable proof that the bugfix actually fixed the bug&lt;/li&gt;
&lt;li&gt;CI still passes at every commit&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The traditional way to do this is to do a bugfix and add a test in the same commit. But what if the test accidentally already passed before the alleged bugfix and the alleged bugfix didn’t actually work? In that case the added test gives false confidence that the bugfix worked.&lt;/p&gt;
&lt;h2&gt;Alright, show me&lt;/h2&gt;
&lt;p&gt;Here’s a less obvious example.&lt;/p&gt;
&lt;p&gt;Suppose we want to make sure users are not underage,&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Python&quot;&gt;&lt;span class=&quot;syntax-source syntax-python&quot;&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-python&quot;&gt;&lt;span class=&quot;syntax-storage syntax-type syntax-function syntax-python&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;syntax-entity syntax-name syntax-function syntax-python&quot;&gt;&lt;span class=&quot;syntax-meta syntax-generic-name syntax-python&quot;&gt;age_in_years&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-parameters syntax-python&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parameters syntax-begin syntax-python&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-parameters syntax-python&quot;&gt;&lt;span class=&quot;syntax-variable syntax-parameter syntax-python&quot;&gt;birthday&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-separator syntax-parameters syntax-python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;syntax-variable syntax-parameter syntax-python&quot;&gt;today&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parameters syntax-end syntax-python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-python&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-function syntax-begin syntax-python&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;syntax-keyword syntax-control syntax-flow syntax-return syntax-python&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-qualified-name syntax-python&quot;&gt;&lt;span class=&quot;syntax-meta syntax-generic-name syntax-python&quot;&gt;today&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-accessor syntax-dot syntax-python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-generic-name syntax-python&quot;&gt;year&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-operator syntax-arithmetic syntax-python&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-qualified-name syntax-python&quot;&gt;&lt;span class=&quot;syntax-meta syntax-generic-name syntax-python&quot;&gt;birthday&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-accessor syntax-dot syntax-python&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-generic-name syntax-python&quot;&gt;year&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;syntax-meta syntax-function syntax-python&quot;&gt;&lt;span class=&quot;syntax-storage syntax-type syntax-function syntax-python&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;syntax-entity syntax-name syntax-function syntax-python&quot;&gt;&lt;span class=&quot;syntax-meta syntax-generic-name syntax-python&quot;&gt;can_access&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-parameters syntax-python&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parameters syntax-begin syntax-python&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-parameters syntax-python&quot;&gt;&lt;span class=&quot;syntax-variable syntax-parameter syntax-python&quot;&gt;birthday&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-separator syntax-parameters syntax-python&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;syntax-variable syntax-parameter syntax-python&quot;&gt;today&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-parameters syntax-end syntax-python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-python&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-function syntax-begin syntax-python&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;syntax-keyword syntax-control syntax-flow syntax-return syntax-python&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python&quot;&gt;18&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-operator syntax-comparison syntax-python&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-function-call syntax-python&quot;&gt;&lt;span class=&quot;syntax-meta syntax-qualified-name syntax-python&quot;&gt;&lt;span class=&quot;syntax-variable syntax-function syntax-python&quot;&gt;age_in_years&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function-call syntax-arguments syntax-python&quot;&gt;
        &lt;span class=&quot;syntax-meta syntax-qualified-name syntax-python&quot;&gt;&lt;span class=&quot;syntax-meta syntax-generic-name syntax-python&quot;&gt;birthday&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-separator syntax-arguments syntax-python&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;syntax-meta syntax-qualified-name syntax-python&quot;&gt;&lt;span class=&quot;syntax-meta syntax-generic-name syntax-python&quot;&gt;today&lt;/span&gt;&lt;/span&gt;
    &lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You notice that this age check is buggy. It’s only considering the years. If it’s October 2026, but you were born on December 2008, you are not 18 yet.&lt;/p&gt;
&lt;p&gt;To fix it, the problem is just an off-by-one.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Diff&quot;&gt;&lt;span class=&quot;syntax-source syntax-diff&quot;&gt;diff --git a/dates.py b/dates.py
&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-from-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-from-file syntax-diff&quot;&gt;---&lt;/span&gt; a/dates.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-to-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-to-file syntax-diff&quot;&gt;+++&lt;/span&gt; b/dates.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-range syntax-unified&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-toc-list syntax-line-number syntax-diff&quot;&gt;-4,7 +4,7&lt;/span&gt; &lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt;&lt;/span&gt; def age_in_years(birthday, today):
     return today.year - birthday.year

 def can_access(birthday, today):
&lt;span class=&quot;syntax-markup syntax-deleted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-deleted syntax-diff&quot;&gt;-&lt;/span&gt;    return 18 &amp;lt;= age_in_years(
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;    return 18 &amp;lt; age_in_years(
&lt;/span&gt;         birthday,
         today
     )
diff --git a/test_date.py b/test_date.py
&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-from-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-from-file syntax-diff&quot;&gt;---&lt;/span&gt; a/test_date.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-to-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-to-file syntax-diff&quot;&gt;+++&lt;/span&gt; b/test_date.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-range syntax-unified&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-toc-list syntax-line-number syntax-diff&quot;&gt;-0,0 +1,5&lt;/span&gt; &lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;def test_can_access():
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;   assert can_access(
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;       date(2007, 1, 1),
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;       date(2026, 1, 1)
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;   )
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The astute reader will observe the problem isn’t in the &lt;code&gt;can_access&lt;/code&gt; function but in the age calculation. The bugfix isn’t an actual bugfix and the proposed test actually passes both before and after the proposed fix.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;Kluever Maneuver&lt;/em&gt; would have prevented this.&lt;/p&gt;
&lt;p&gt;We wrongly check that someone born on New Year’s Eve in 2008 is eighteen on New Year’s Day in 2026.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Diff&quot;&gt;&lt;span class=&quot;syntax-source syntax-diff&quot;&gt;commit 1

diff --git a/test_date.py b/test_date.py
&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-from-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-from-file syntax-diff&quot;&gt;---&lt;/span&gt; a/test_date.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-to-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-to-file syntax-diff&quot;&gt;+++&lt;/span&gt; b/test_date.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-range syntax-unified&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-toc-list syntax-line-number syntax-diff&quot;&gt;-0,0 +1,5&lt;/span&gt; &lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;def test_can_access():
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;   assert can_access(
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;       date(2008, 12, 31),
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;       date(2026, 1, 1)
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;   )
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we fix the age calculation and flip the test.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Diff&quot;&gt;&lt;span class=&quot;syntax-source syntax-diff&quot;&gt;commit 2

diff --git a/dates.py b/dates.py
&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-from-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-from-file syntax-diff&quot;&gt;---&lt;/span&gt; a/dates.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-to-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-to-file syntax-diff&quot;&gt;+++&lt;/span&gt; b/dates.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-range syntax-unified&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-toc-list syntax-line-number syntax-diff&quot;&gt;-1,7 +1,10&lt;/span&gt; &lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;from dateutil.relativedelta import relativedelta
&lt;/span&gt;
 def age_in_years(birthday, today):
&lt;span class=&quot;syntax-markup syntax-deleted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-deleted syntax-diff&quot;&gt;-&lt;/span&gt;    return today.year - birthday.year
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;    return relativedelta(
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;        today,
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;        birthday
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;    ).years
&lt;/span&gt;
 def can_access(birthday, today):
     return 18 &amp;lt;= age_in_years(
diff --git a/test_date.py b/test_date.py
&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-from-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-from-file syntax-diff&quot;&gt;---&lt;/span&gt; a/test_date.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-to-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-to-file syntax-diff&quot;&gt;+++&lt;/span&gt; b/test_date.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-range syntax-unified&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-toc-list syntax-line-number syntax-diff&quot;&gt;-1,5 +1,5&lt;/span&gt; &lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt;
&lt;/span&gt; def test_can_access():
&lt;span class=&quot;syntax-markup syntax-deleted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-deleted syntax-diff&quot;&gt;-&lt;/span&gt;   assert test_can_access(
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;   assert not test_can_access(
&lt;/span&gt;        date(2008, 12, 31),
        date(2026, 1, 1)
    )
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Shouldn’t we use &lt;code&gt;XFAIL&lt;/code&gt; instead?&lt;/h2&gt;
&lt;p&gt;Okay, first of all, not every testing framework has an &lt;code&gt;XFAIL&lt;/code&gt; equivalent (sigh, Java…).&lt;/p&gt;
&lt;p&gt;Setting that aside, a positive passing test isn’t completely logically equivalent to a positive failing test. Going back to our addition example, if we were to add this test,&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Diff&quot;&gt;&lt;span class=&quot;syntax-source syntax-diff&quot;&gt;Commit 1

diff --git a/test_arith.py b/test_arith.py
&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-from-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-from-file syntax-diff&quot;&gt;---&lt;/span&gt; a/test_arith.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-to-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-to-file syntax-diff&quot;&gt;+++&lt;/span&gt; b/test_arith.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-range syntax-unified&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-toc-list syntax-line-number syntax-diff&quot;&gt;-0,0 +1,2&lt;/span&gt; &lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;@pytest.mark.xfail
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;def test_add(a, b):
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;   assert add(2, 2) == 4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This test only tells us that the current addition isn’t four, but it doesn’t tell us exactly what the addition is. Depending on the nature of the bug, a positive failing test might not exemplify as clearly what exactly the bug is. Knowing that two plus two is five might make it easier to understand how to fix the bug.&lt;/p&gt;
&lt;p&gt;That being said, using &lt;code&gt;XFAIL&lt;/code&gt; is in general roughly equivalent. If for some reason we can’t currently fix the bug right now, only record it, an &lt;code&gt;XFAIL&lt;/code&gt; is better, since we expect we’ll be carrying this around for a longer time.&lt;/p&gt;
&lt;h2&gt;What about bug tracking?&lt;/h2&gt;
&lt;p&gt;Ah, yes, it’s also a good idea to log a bug in your tracker.&lt;/p&gt;
&lt;p&gt;Reference the bug in your first commit.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Diff&quot;&gt;&lt;span class=&quot;syntax-source syntax-diff&quot;&gt;add a test showing the bug

diff --git a/test_arith.py b/test_arith.py
&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-from-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-from-file syntax-diff&quot;&gt;---&lt;/span&gt; a/test_arith.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-to-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-to-file syntax-diff&quot;&gt;+++&lt;/span&gt; b/test_arith.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-range syntax-unified&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-toc-list syntax-line-number syntax-diff&quot;&gt;-0,0 +1,2&lt;/span&gt; &lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;FIXME: bug #1729
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;def test_add(a, b):
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;   assert add(2, 2) == 5
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Record the fix in the second commit:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Diff&quot;&gt;&lt;span class=&quot;syntax-source syntax-diff&quot;&gt;remove off-by-one error

fixes: #1729

diff --git a/arith.py b/arith.py
&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-from-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-from-file syntax-diff&quot;&gt;---&lt;/span&gt; a/arith.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-to-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-to-file syntax-diff&quot;&gt;+++&lt;/span&gt; b/arith.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-range syntax-unified&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-toc-list syntax-line-number syntax-diff&quot;&gt;-1,2 +1,2&lt;/span&gt; &lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt;
&lt;/span&gt; def add(a, b):
&lt;span class=&quot;syntax-markup syntax-deleted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-deleted syntax-diff&quot;&gt;-&lt;/span&gt;   return a + b + 1
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;   return a + b
&lt;/span&gt;diff --git a/test_arith.py b/test_arith.py
&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-from-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-from-file syntax-diff&quot;&gt;---&lt;/span&gt; a/test_arith.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-header syntax-to-file&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-to-file syntax-diff&quot;&gt;+++&lt;/span&gt; b/test_arith.py
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-diff syntax-range syntax-unified&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-toc-list syntax-line-number syntax-diff&quot;&gt;-1,2 +1,2&lt;/span&gt; &lt;span class=&quot;syntax-punctuation syntax-definition syntax-range syntax-diff&quot;&gt;@@&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-deleted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-deleted syntax-diff&quot;&gt;-&lt;/span&gt;FIXME: bug #1729
&lt;/span&gt; def test_add(a, b):
&lt;span class=&quot;syntax-markup syntax-deleted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-deleted syntax-diff&quot;&gt;-&lt;/span&gt;   assert add(2, 2) == 5
&lt;/span&gt;&lt;span class=&quot;syntax-markup syntax-inserted syntax-diff&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-inserted syntax-diff&quot;&gt;+&lt;/span&gt;   assert add(2, 2) == 4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Okay but why “Kluever Maneuver”?&lt;/h2&gt;
&lt;p&gt;Oh. Because my colleague &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://github.com/kluever&quot;&gt;Kurt Kluever&lt;/a&gt; taught it to me, and I immediately think back to him when I think of this technique. He usualy calls it “terrible tests”, as in “Jordi, can you please write a terrible test for this?” and off I go to write a test asserting something I know to be wrong.&lt;/p&gt;
</content:encoded>
    <category>news</category>
    <category>testing</category>
  </item>
</channel>
</rss>
