<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mahiro Hirakawa</title>
    <description>The latest articles on DEV Community by Mahiro Hirakawa (@mahirhir).</description>
    <link>https://dev.to/mahirhir</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3937147%2F66fce836-aa25-43f0-bb5f-632fc17ebf44.jpeg</url>
      <title>DEV Community: Mahiro Hirakawa</title>
      <link>https://dev.to/mahirhir</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mahirhir"/>
    <language>en</language>
    <item>
      <title>My safety check was an assert. Five lines made the module refuse to load without it.</title>
      <dc:creator>Mahiro Hirakawa</dc:creator>
      <pubDate>Sun, 06 Sep 2026 18:50:12 +0000</pubDate>
      <link>https://dev.to/mahirhir/my-safety-check-was-an-assert-five-lines-made-the-module-refuse-to-load-without-it-36n3</link>
      <guid>https://dev.to/mahirhir/my-safety-check-was-an-assert-five-lines-made-the-module-refuse-to-load-without-it-36n3</guid>
      <description>&lt;p&gt;&lt;code&gt;assert isinstance(flag, bool)&lt;/code&gt; reads like a check. Under &lt;code&gt;python -O&lt;/code&gt; it is not there at all, and nothing at the call site says so. The usual advice is to stop writing safety checks as asserts. There is a better answer: let the module refuse to be imported in the mode where its checks evaporate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;__debug__&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;this module&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s checks are asserts; refusing to run with -O&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python useguard.py
&lt;span class="go"&gt;guard loaded, gate(True) = True
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python &lt;span class="nt"&gt;-O&lt;/span&gt; useguard.py&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="gp"&gt;RuntimeError: this module's checks are asserts;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;refusing to run with &lt;span class="nt"&gt;-O&lt;/span&gt;
&lt;span class="go"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Five lines, and the failure moves from the approval to the import. A deployment that will not start is a different kind of problem from a gate that quietly stopped gating.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the runtime will and will not tell you
&lt;/h2&gt;

&lt;p&gt;Two different questions get confused here, and they have different answers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What has this image been imported under?&lt;/strong&gt; The optimization level is stamped into the bytecode cache filename, so the artifacts accumulate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python use.py &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; python &lt;span class="nt"&gt;-O&lt;/span&gt; use.py &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; python &lt;span class="nt"&gt;-OO&lt;/span&gt; use.py
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ls &lt;/span&gt;__pycache__
&lt;span class="go"&gt;m.cpython-314.opt-1.pyc
m.cpython-314.opt-2.pyc
m.cpython-314.pyc
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is real evidence and it survives the process that made it. It is also easy to lose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; __pycache__ &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;PYTHONDONTWRITEBYTECODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 python &lt;span class="nt"&gt;-O&lt;/span&gt; use.py
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ls &lt;/span&gt;__pycache__
&lt;span class="go"&gt;(no such directory)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A read-only image layer does the same thing. So the artifact answers a forensic question, and answers it only sometimes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is this process running under right now?&lt;/strong&gt; That one is reliable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python probe.py
&lt;span class="go"&gt;sys.flags.optimize = 0 | __debug__ = True
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python &lt;span class="nt"&gt;-O&lt;/span&gt; probe.py
&lt;span class="go"&gt;sys.flags.optimize = 1 | __debug__ = False
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;question&lt;/th&gt;
&lt;th&gt;source&lt;/th&gt;
&lt;th&gt;can it be missing?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;what has been imported&lt;/td&gt;
&lt;td&gt;&lt;code&gt;__pycache__/*.opt-N.pyc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;yes: &lt;code&gt;PYTHONDONTWRITEBYTECODE&lt;/code&gt;, or a read-only layer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;what is running now&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;sys.flags.optimize&lt;/code&gt;, &lt;code&gt;__debug__&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The guard uses the second one, which is why it works in an image with no &lt;code&gt;__pycache__&lt;/code&gt; at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "just don't use asserts" is the weaker rule
&lt;/h2&gt;

&lt;p&gt;It is advice to every future author of every line in the module, and review is what enforces it. The import guard is one line. The interpreter enforces that one, including over asserts nobody has written yet.&lt;/p&gt;

&lt;p&gt;It also fails in the right direction. Someone deploying with &lt;code&gt;-O&lt;/code&gt; for speed gets a crash with a sentence explaining the conflict, at startup, in their own terminal. The alternative is that the same person deploys successfully and finds out later, from an action nobody approved.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does not do
&lt;/h2&gt;

&lt;p&gt;It does not make asserts a good way to express a safety invariant. If the check matters, &lt;code&gt;if not isinstance(...): raise&lt;/code&gt; is still better, and the guard is what you put on top of the module while the asserts are still in it.&lt;/p&gt;

&lt;p&gt;It also stops at the module boundary. A module with the guard is safe under &lt;code&gt;-O&lt;/code&gt;; a module in the same process without it is not, and nothing coordinates the two.&lt;/p&gt;

&lt;p&gt;Both of those cost more than five lines. This costs five.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Measured on CPython 3.14.4 (Windows) and cross-checked against 3.14.6 on macOS by &lt;a href="https://dev.to/vinhnguyenthanhdn"&gt;@vinhnguyenthanhdn&lt;/a&gt;, who pointed out the &lt;code&gt;__pycache__&lt;/code&gt; artifact in the first place. The three-file listing and the &lt;code&gt;PYTHONDONTWRITEBYTECODE&lt;/code&gt; result are reproduced from runs on both.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>security</category>
      <category>testing</category>
      <category>debugging</category>
    </item>
    <item>
      <title>git commit with a pathspec ignored my index and committed the file as it sat on disk</title>
      <dc:creator>Mahiro Hirakawa</dc:creator>
      <pubDate>Sat, 05 Sep 2026 17:23:59 +0000</pubDate>
      <link>https://dev.to/mahirhir/git-commit-with-a-pathspec-ignored-my-index-and-committed-the-file-as-it-sat-on-disk-262g</link>
      <guid>https://dev.to/mahirhir/git-commit-with-a-pathspec-ignored-my-index-and-committed-the-file-as-it-sat-on-disk-262g</guid>
      <description>&lt;p&gt;Run this in an empty directory. It takes about fifteen seconds and it is the whole article.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git init &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git config user.email t@t &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git config user.name t
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'v1\n'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; a.txt &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git add &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit &lt;span class="nt"&gt;-qm&lt;/span&gt; base
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'v2-staged\n'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; a.txt &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git add a.txt     &lt;span class="c"&gt;# stage a version&lt;/span&gt;
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'v3-worktree-only\n'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; a.txt               &lt;span class="c"&gt;# then keep typing&lt;/span&gt;
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git show :a.txt
&lt;span class="go"&gt;v2-staged
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;a.txt
&lt;span class="go"&gt;v3-worktree-only

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git commit &lt;span class="nt"&gt;-qm&lt;/span&gt; &lt;span class="s1"&gt;'commit with pathspec'&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; a.txt
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git show HEAD:a.txt
&lt;span class="go"&gt;v3-worktree-only
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git status &lt;span class="nt"&gt;--porcelain&lt;/span&gt;
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The staged version is not in the commit. The working tree is clean, so nothing afterwards suggests a choice was made.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Correction (2026-09-07).&lt;/strong&gt; I first wrote that the staged version was "not anywhere". That is wrong, and &lt;a href="https://dev.to/vinhnguyenthanhdn"&gt;@vinhnguyenthanhdn&lt;/a&gt; corrected it in the comments. &lt;code&gt;git add&lt;/code&gt; writes the blob into the object store before it touches the index, so the staged content survives as an unreachable object until something prunes it. Measured on git 2.54.0.windows.1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git fsck &lt;span class="nt"&gt;--unreachable&lt;/span&gt;
&lt;span class="go"&gt;unreachable blob f531e07edd848253b8d61160ac743ae4e3d09888
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git cat-file &lt;span class="nt"&gt;-p&lt;/span&gt; f531e07edd848253b8d61160ac743ae4e3d09888
&lt;span class="go"&gt;v2-staged
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the diagnosis has a recovery attached to it, and "lost" was the wrong word for "unreferenced".&lt;/p&gt;

&lt;p&gt;He also named a harsher variant, which reproduces here too: stage a modification, then delete the file from the working tree, then commit with the same pathspec.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'v2-staged
&lt;/span&gt;&lt;span class="gp"&gt;' &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;a.txt &amp;amp;&amp;amp; git add a.txt
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;rm a.txt
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;git commit -m "pathspec after removal" -- a.txt
&lt;/span&gt;&lt;span class="go"&gt; 1 file changed, 1 deletion(-)
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git status &lt;span class="nt"&gt;--porcelain&lt;/span&gt;      &lt;span class="c"&gt;# nothing&lt;/span&gt;
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git cat-file &lt;span class="nt"&gt;-e&lt;/span&gt; HEAD:a.txt&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="go"&gt;128
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first case at least leaves something odd in the diff. This one does not: a file caught mid-edit is recorded as a deliberate deletion, on a clean tree, and the staged content sits unreferenced in the object store while the history tells a coherent story about someone removing the file on purpose.&lt;/p&gt;

&lt;p&gt;This is documented behaviour, not a bug. Naming paths on &lt;code&gt;git commit&lt;/code&gt; means "commit these paths as they are now", and the index is bypassed for them. Measured on git 2.54.0.windows.1.&lt;/p&gt;

&lt;p&gt;The variant that looks like it would help does not:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git commit &lt;span class="nt"&gt;-qm&lt;/span&gt; &lt;span class="s1"&gt;'include mode'&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; a.txt
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git show HEAD:a.txt
&lt;span class="go"&gt;v3-worktree
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-i&lt;/code&gt; adds the rest of the index to the commit. The named path still comes off the disk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it bit me
&lt;/h2&gt;

&lt;p&gt;Two commits in my own repository, one day apart, same shape.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;b3a9236&lt;/code&gt; was made with named paths while another writer was editing the same tree. Eleven files, 549 insertions. Some of those insertions were rows that writer had not finished. Naming the paths did not stop it, because the paths were right and the versions were not.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ba03c95&lt;/code&gt; is the cruder relative. It was made with &lt;code&gt;git add&lt;/code&gt; on a directory, and it captured an audit file at 74 lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git show ba03c95:DB/.../AUDIT_FINAL_2_PROOF_TEST_SYNC_2026-09-05.md | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;span class="go"&gt;74
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; &amp;lt; DB/.../AUDIT_FINAL_2_PROOF_TEST_SYNC_2026-09-05.md
&lt;span class="go"&gt;198
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The committed 74 lines are a byte-identical prefix of the 198 that exist now. That is what a file looks like when you photograph it mid-sentence. Nothing failed; the commit is clean and its message describes work that was 37 percent written.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I got wrong
&lt;/h2&gt;

&lt;p&gt;I moved to naming paths precisely because a broad &lt;code&gt;git add&lt;/code&gt; had swept up something half-written. The move was reasonable and it fixed the wrong half of the problem. A pathspec narrows which files go in. It says nothing about which version of each one, and on that question it takes the least careful answer available.&lt;/p&gt;

&lt;p&gt;Underneath that is the actual error, which is not about git at all: I let two writers work in one tree and then went looking for a command that would make that safe. There isn't one. &lt;code&gt;git stash&lt;/code&gt; is worse; I tried it once against a concurrent working tree and got the file back only because the other side had not written in the interval.&lt;/p&gt;

&lt;p&gt;What I run now is boring. Stage deliberately, then &lt;code&gt;git commit&lt;/code&gt; with no pathspec at all, so that what lands is exactly what I looked at. One writer per tree, and if a second one is needed, it gets its own worktree.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did not check
&lt;/h2&gt;

&lt;p&gt;Whether the same holds on older git versions. The behaviour is old and documented, and I measured one version.&lt;/p&gt;

&lt;p&gt;I have not audited how many of my past commits carry a file that was mid-edit. The two above were found because someone noticed the content, not by a search, so the count is a floor and not a total.&lt;/p&gt;

&lt;p&gt;I also have not tested this against a git GUI or an editor's built-in staging view. Those wrap the same plumbing, but I did not run them, so I am not going to tell you what they do.&lt;/p&gt;

&lt;p&gt;The reason I care about the second commit at all is that its content is an audit of my own instruments. A truncated audit that looks complete is worse than no audit, and the only reason it was caught is that a human read the file and found it ended in the middle of a sentence.&lt;/p&gt;

&lt;p&gt;Trace: the transcripts above were run on 2026-09-05.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/TraceFold/tracefold" rel="noopener noreferrer"&gt;TraceFold/tracefold&lt;/a&gt; is the public tree of the project these commits belong to, and &lt;a href="https://github.com/TraceFold/tracefold/blob/main/tools/e2e.sh" rel="noopener noreferrer"&gt;tools/e2e.sh&lt;/a&gt; is the script that is supposed to catch a tree in a state like that.&lt;/p&gt;

</description>
      <category>git</category>
      <category>devops</category>
      <category>debugging</category>
      <category>testing</category>
    </item>
    <item>
      <title>A red I expected hid an instrument that was reading an empty directory</title>
      <dc:creator>Mahiro Hirakawa</dc:creator>
      <pubDate>Sat, 05 Sep 2026 17:23:23 +0000</pubDate>
      <link>https://dev.to/mahirhir/a-red-i-expected-hid-an-instrument-that-was-reading-an-empty-directory-2ph8</link>
      <guid>https://dev.to/mahirhir/a-red-i-expected-hid-an-instrument-that-was-reading-an-empty-directory-2ph8</guid>
      <description>&lt;p&gt;One row in my project's coverage table read &lt;code&gt;0/13&lt;/code&gt;. Later it read &lt;code&gt;0/19&lt;/code&gt;. It read a zero at every commit for a full day, and I looked at it every time without stopping, because zero was the number I expected. The work it measures was not finished. A red row on unfinished work is not news.&lt;/p&gt;

&lt;p&gt;The row was measuring nothing. Here is the line that decided it, from the crate that owns the check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;SEMANTIC_MAPS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"UnderstandRTSync/semantic"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That path was resolved against the repository root. The directory it names is not inside the repository; it is a sibling of it. So the reader opened a path that does not exist, found no files, and reported honest arithmetic over an empty set. Zero of thirteen. Then someone added crates and it became zero of nineteen, which looks even more like a project making slow progress.&lt;/p&gt;

&lt;p&gt;The denominator was moving. The numerator could not move, and nothing in the setup could tell me that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it survived an audit
&lt;/h2&gt;

&lt;p&gt;It survived because two rows next to it were red for real reasons. A file ledger at &lt;code&gt;0/289&lt;/code&gt;. A document census at &lt;code&gt;0/1916&lt;/code&gt;. Both genuinely at the start of long jobs.&lt;/p&gt;

&lt;p&gt;An expected red hides inside a row of expected reds. My audit read the table as a progress bar and asked whether the numbers were moving, not whether the instrument could produce a number other than zero.&lt;/p&gt;

&lt;p&gt;The general form: a check that can only ever fail is indistinguishable from a check that is failing, and the difference matters more than any single verdict on the board.&lt;/p&gt;

&lt;h2&gt;
  
  
  The repair is a positive control, not a fix
&lt;/h2&gt;

&lt;p&gt;Pointing the path at the right directory takes one line. That was not the interesting part. The test that went in with it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[test]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;semantic_map_coverage_counts_the_maps_it_can_see&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and its comment states the discriminator plainly: pointed at an empty directory it must read &lt;code&gt;0/n&lt;/code&gt;, at a directory holding one map it must read &lt;code&gt;1/n&lt;/code&gt;, and at the real directory exactly the number of maps on disk. A coverage that always reports zero and a coverage that always reports &lt;code&gt;n/n&lt;/code&gt; are then two different, visible failures.&lt;/p&gt;

&lt;p&gt;The environment variable exists only so the test can move the directory under the instrument's feet. How full the real directory happens to be is never asserted, because that number is the project's business and changes daily.&lt;/p&gt;

&lt;p&gt;One more thing changed with it. The denominator used to be a hand-walked file count. It is now derived from the workspace members in &lt;code&gt;Cargo.toml&lt;/code&gt;, so a new crate raises the denominator whether or not anyone remembers to update a list. A denominator I maintain by hand is a denominator that agrees with me.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I got wrong
&lt;/h2&gt;

&lt;p&gt;I wrote the rule "every control needs a planted negative" early and followed it. Every check on this project has a case that must turn it red.&lt;/p&gt;

&lt;p&gt;I had no rule for the opposite direction, and this row is what that gap looks like: a check that had never once been shown a world in which it should say something other than zero. A planted negative proves a check can fail. A planted positive proves it can succeed. I had built half of the pair and called it discipline.&lt;/p&gt;

&lt;p&gt;The second mistake is the one I keep making. I read the red as a statement about the project when it was a statement about the reader. That is the same shape as reading an empty search result as an absence, which I have written about before and evidently had not internalised.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did not check
&lt;/h2&gt;

&lt;p&gt;Two rows in the same table are still red for reasons I believe, and neither has a planted positive yet: the file ledger and the document census. I believe them for exactly the reason I believed this one. That is not a good enough reason and they are next.&lt;/p&gt;

&lt;p&gt;I have not audited the rest of the tree for paths resolved against the wrong root. This one was found because a lane went looking at a specific instrument, not by a search for the pattern.&lt;/p&gt;

&lt;p&gt;The historical rows stay as written. The record is append-only, so a day of &lt;code&gt;0/13&lt;/code&gt; remains in it, wrong, with this entry beside it saying why.&lt;/p&gt;

&lt;p&gt;Trace: the constant and the test are at &lt;code&gt;crates/gate/src/lib.rs&lt;/code&gt;, lines 81 and 1839.&lt;/p&gt;

&lt;p&gt;Repository: this rebuild is private while it is being cut. Its public predecessor is &lt;a href="https://github.com/TraceFold/tracefold" rel="noopener noreferrer"&gt;TraceFold/tracefold&lt;/a&gt;, and &lt;a href="https://github.com/TraceFold/tracefold/blob/main/docs/LIMITS.md" rel="noopener noreferrer"&gt;docs/LIMITS.md&lt;/a&gt; is where that project writes down what its own checks do not cover.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>rust</category>
      <category>debugging</category>
      <category>devops</category>
    </item>
    <item>
      <title>2500 tests in my public repository and nothing was running them</title>
      <dc:creator>Mahiro Hirakawa</dc:creator>
      <pubDate>Sat, 05 Sep 2026 15:51:42 +0000</pubDate>
      <link>https://dev.to/mahirhir/2500-tests-in-my-public-repository-and-nothing-was-running-them-3chn</link>
      <guid>https://dev.to/mahirhir/2500-tests-in-my-public-repository-and-nothing-was-running-them-3chn</guid>
      <description>&lt;p&gt;Someone asked me a simple question about my own project: what are all those tests actually for. The honest answer turned out to be that they were not for anything, because nothing was running them.&lt;/p&gt;

&lt;p&gt;Three findings, each verified separately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;There was no CI.&lt;/strong&gt; No &lt;code&gt;.github/workflows/&lt;/code&gt; in the tree and none in its history. Every test in that repository ran only when a person typed &lt;code&gt;cargo test&lt;/code&gt; by hand, which meant they ran when I felt like it and never on a pull request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One crate was not in the workspace at all.&lt;/strong&gt; &lt;code&gt;crates/gx-adapter-time&lt;/code&gt; was neither in the &lt;code&gt;members&lt;/code&gt; list nor in &lt;code&gt;exclude&lt;/code&gt;, and cargo answers that state with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;current package believes it's in a workspace when it's not
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is no build path to that directory. It shipped in the published repository, so every person who cloned the project received a directory that cannot compile.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The bundled end-to-end script could not pass in the bundled tree.&lt;/strong&gt; &lt;code&gt;tools/e2e.sh&lt;/code&gt; carried a floor of &lt;code&gt;MIN_PROBES=2822&lt;/code&gt; and the tree it shipped with had roughly 2500. The script exits 16 on a floor violation. It shipped exiting 16.&lt;/p&gt;

&lt;p&gt;Counted today on the frozen tree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-rn&lt;/span&gt; &lt;span class="s1"&gt;'#\[test\]'&lt;/span&gt; &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;.rs &lt;span class="nb"&gt;.&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;span class="go"&gt;2485
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-rn&lt;/span&gt; &lt;span class="s1"&gt;'#\[tokio::test'&lt;/span&gt; &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;.rs &lt;span class="nb"&gt;.&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;span class="go"&gt;89
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*.rs'&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;span class="go"&gt;592
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The one that stung
&lt;/h2&gt;

&lt;p&gt;Adding the missing crate to the workspace made ten tests run for the first time. All ten passed. One of them is named:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-rn&lt;/span&gt; &lt;span class="s1"&gt;'the_undo_window_closes_because_firedness_is_inside_the_fingerprint'&lt;/span&gt; &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;.rs &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="go"&gt;./crates/gx-adapter-time/tests/wm4a_time_substrate.rs:170
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the invariant the product is sold on. It is the sentence in the README rendered as an assertion. It had never executed.&lt;/p&gt;

&lt;p&gt;The pattern is not random. The core claim gets the most careful test and the least exercise, because the careful test lives in the newest crate, and the newest crate is the one nobody remembered to wire into the build.&lt;/p&gt;

&lt;h2&gt;
  
  
  The root that was already written down
&lt;/h2&gt;

&lt;p&gt;The public workspace root explains an adjacent failure in its own header, and I had read it without connecting the two:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before this split the public &lt;code&gt;Cargo.toml&lt;/code&gt; was the private one verbatim, so it declared 19 members while a public clone carried 14, and cargo refuses to load a workspace whose member manifest is missing. Measured on an anonymous fresh clone before this fix: &lt;code&gt;cargo metadata&lt;/code&gt; exit 101, &lt;code&gt;cargo build --workspace&lt;/code&gt; exit 101.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every cargo command in the published repository failed before it read a line of Rust. The tests were not failing. They were unreachable, which produces no output at all, and no output is the state a repository sits in comfortably for months.&lt;/p&gt;

&lt;p&gt;There is a smaller trap recorded in the same file. A hand-written parser that reads the members array to cross-check the crate count treats every line between the brackets as a member, so a two-line comment placed among the paths was counted as two crates and a test reported 20 against 18, naming a fragment of prose as a crate name.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I got wrong
&lt;/h2&gt;

&lt;p&gt;I have argued in public that code is the proof and that a test suite is internal hygiene. I still think the second half of that is right. What I had not noticed is that I was using the size of the suite as evidence anyway, in my own head, as a reason to feel finished.&lt;/p&gt;

&lt;p&gt;2500 assertions that nobody executes are not a weak proof. They are a document formatted like code. The number was doing the work that a green run should have been doing, and the number is the easiest thing in the world to produce.&lt;/p&gt;

&lt;p&gt;Fixed and pushed: the crate is in the members list on &lt;code&gt;main&lt;/code&gt; at &lt;code&gt;Cargo.toml:44&lt;/code&gt;, and &lt;code&gt;.github/workflows/ci.yml&lt;/code&gt; now exists, which it did not when this was audited. The side effect of the member fix is that &lt;code&gt;cargo metadata --locked&lt;/code&gt; exits 0 again, because the published lock file had been left describing the private workspace.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did not check
&lt;/h2&gt;

&lt;p&gt;My counts above are test attributes in the source, not tests executed. I have not run the suite on this machine, which has no Rust toolchain, so the last number I trust for pass counts is the ledger's.&lt;/p&gt;

&lt;p&gt;Whether the other 2500 are worth keeping is a separate question I have only partly answered. A rough classification put around half of them in reach of a smaller end-to-end check, and about a quarter genuinely out of reach of one, tamper cases and signature paths among them. That classification was a reading, not a measurement, and I would not defend the percentages.&lt;/p&gt;

&lt;p&gt;I also do not know how long the unreachable crate had been unreachable. The audit did not date it and I have not gone back through the history to find out.&lt;/p&gt;

&lt;p&gt;Trace: the greps, the file paths and the presence of the workflow on &lt;code&gt;main&lt;/code&gt; were checked on 2026-09-05.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/TraceFold/tracefold" rel="noopener noreferrer"&gt;TraceFold/tracefold&lt;/a&gt;, where &lt;a href="https://github.com/TraceFold/tracefold/blob/main/tools/e2e.sh" rel="noopener noreferrer"&gt;tools/e2e.sh&lt;/a&gt; is the script that used to ship exiting 16.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>testing</category>
      <category>ci</category>
      <category>opensource</category>
    </item>
    <item>
      <title>A maintainer closed all four of my pull requests in one minute, and the close was correct</title>
      <dc:creator>Mahiro Hirakawa</dc:creator>
      <pubDate>Sat, 05 Sep 2026 15:51:06 +0000</pubDate>
      <link>https://dev.to/mahirhir/a-maintainer-closed-all-four-of-my-pull-requests-in-one-minute-and-the-close-was-correct-3948</link>
      <guid>https://dev.to/mahirhir/a-maintainer-closed-all-four-of-my-pull-requests-in-one-minute-and-the-close-was-correct-3948</guid>
      <description>&lt;p&gt;On 2026-09-05 at 00:37Z an OpenAI maintainer closed an issue I had opened and the four pull requests attached to it. Checked through the API today:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;gh api repos/openai/openai-agents-python/issues/4845 &lt;span class="nt"&gt;--jq&lt;/span&gt; &lt;span class="s1"&gt;'.state, .state_reason'&lt;/span&gt;
&lt;span class="go"&gt;closed
completed

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for &lt;/span&gt;n &lt;span class="k"&gt;in &lt;/span&gt;4846 4847 4848 4849&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;gh api repos/openai/openai-agents-python/pulls/&lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="gp"&gt;    --jq '.state + " merged=" + (.merged|tostring)';&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;span class="go"&gt;closed merged=false
closed merged=false
closed merged=false
closed merged=false
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;His reason, in full:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The examples return values outside the declared boolean callback contract. They establish the current truthiness behavior, but do not establish an SDK-owned untyped input boundary or a bypass with a supported callback result. Please keep approval decisions explicitly boolean in application code. I am closing these proposals rather than introducing a new validation contract across tool execution paths. A concrete supported-path bypass would warrant reopening the issue.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;He is right, and I want to say why before I say what it cost me.&lt;/p&gt;

&lt;h2&gt;
  
  
  The finding was real and the argument was not
&lt;/h2&gt;

&lt;p&gt;The setting is a human-approval gate on tool calls. It accepts either a boolean or a callable returning a boolean, and the result is used in a truthiness test. So a predicate with an unhandled branch returns &lt;code&gt;None&lt;/code&gt;, &lt;code&gt;None&lt;/code&gt; is falsy, and the approval step is skipped rather than taken. My four patches each validated with &lt;code&gt;isinstance(x, bool)&lt;/code&gt; instead of trusting the truthy read.&lt;/p&gt;

&lt;p&gt;The maintainer's position is that the declared type is &lt;code&gt;bool&lt;/code&gt;, that returning &lt;code&gt;None&lt;/code&gt; from it is the caller breaking the contract, and that he is not going to add an input-validation layer across every tool execution path to catch callers doing that. Those are three defensible sentences and none of them require him to agree that my examples matter.&lt;/p&gt;

&lt;p&gt;He also named the exact condition under which he would reopen: a bypass reached with a value the contract supports. That is a good gate. It is falsifiable. It is his to set. It tells me precisely what evidence would count.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it cost me, which is the point of writing this
&lt;/h2&gt;

&lt;p&gt;I had been describing this defect class in public as frameworks being broken. That line is now dead for this one, because the vendor said in writing that approval decisions belong in application code, explicitly boolean, on the application's side of the line.&lt;/p&gt;

&lt;p&gt;If the vendor puts the responsibility on the application, then the thing worth auditing is not the framework. It is the application, and specifically the boundary where somebody's own predicate meets somebody else's truthiness test. That is a smaller and more honest claim than the one I was making, and it happens to point at exactly the code a buyer would be paying to have read.&lt;/p&gt;

&lt;p&gt;I got there by being told, not by checking. The claim outran the evidence I had, which was four reachability findings against a contract violation, and reachability is not exploitation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The thread I am not pulling
&lt;/h2&gt;

&lt;p&gt;One asymmetry survives the close. The run path raises an error on the same out-of-contract value, while the realtime path quietly returns false. Identical input, two behaviours, in one SDK. That is arguably the SDK's own behaviour rather than untyped input validation, which puts it inside his line rather than outside it.&lt;/p&gt;

&lt;p&gt;I am not raising it now. Arguing after a close adds no evidence and spends a relationship I would rather keep. His reopening condition is written down, and if I find a bypass with a supported value, that is when I come back.&lt;/p&gt;

&lt;p&gt;The two sibling reports elsewhere are still alive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;gh api repos/pydantic/pydantic-ai/issues/8060 &lt;span class="nt"&gt;--jq&lt;/span&gt; &lt;span class="s1"&gt;'.state'&lt;/span&gt;
&lt;span class="go"&gt;open
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;gh api repos/google/adk-python/issues/7010 &lt;span class="nt"&gt;--jq&lt;/span&gt; &lt;span class="s1"&gt;'.state'&lt;/span&gt;
&lt;span class="go"&gt;open
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two of three, which is a fine outcome for a class of finding that depends on how each project draws its contract boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did not check
&lt;/h2&gt;

&lt;p&gt;Whether any deployed application actually passes a non-boolean predicate result into this setting. I never had that. Reachability in a library is not a demonstrated failure in production, and I should have been saying so from the first sentence.&lt;/p&gt;

&lt;p&gt;Whether the run path and realtime path asymmetry is deliberate. I have not read the history or asked, and I am not going to characterise a design decision I have not investigated.&lt;/p&gt;

&lt;p&gt;Whether the two open reports stay open. They were open when I ran the commands above, and that is the whole claim.&lt;/p&gt;

&lt;p&gt;Trace: the states, the closing comment and the two sibling issues were re-read through the GitHub API on 2026-09-05.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/TraceFold/tracefold" rel="noopener noreferrer"&gt;TraceFold/tracefold&lt;/a&gt; is where the work behind those reports lives, and &lt;a href="https://github.com/TraceFold/tracefold/blob/main/docs/LIMITS.md" rel="noopener noreferrer"&gt;docs/LIMITS.md&lt;/a&gt; is where it writes down what its own checks do not cover.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>python</category>
      <category>career</category>
      <category>testing</category>
    </item>
    <item>
      <title>I wrote that their test harness had no denominator. Their own script header said it first.</title>
      <dc:creator>Mahiro Hirakawa</dc:creator>
      <pubDate>Sat, 05 Sep 2026 15:50:21 +0000</pubDate>
      <link>https://dev.to/mahirhir/i-wrote-that-their-test-harness-had-no-denominator-their-own-script-header-said-it-first-4pbb</link>
      <guid>https://dev.to/mahirhir/i-wrote-that-their-test-harness-had-no-denominator-their-own-script-header-said-it-first-4pbb</guid>
      <description>&lt;p&gt;I was building a comparison table between my project and a much larger one, looking for places where mine is ahead. I opened their regression harness, found a &lt;code&gt;console.warn&lt;/code&gt; on a fixture that fails to load, and wrote the row: their fixture set has no declared denominator, so a fixture can go missing and nothing turns red.&lt;/p&gt;

&lt;p&gt;Then someone made me read one level further out.&lt;/p&gt;

&lt;p&gt;The file that decides which fixtures run is &lt;code&gt;packages/producer/scripts/plan-regression-shards.mjs&lt;/code&gt;. Its header, which I had not opened, says this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Silent drift. A fixture only ran if someone remembered to paste its name into the YAML. 25 fixtures that the harness can run were in no shard at all, some for months, and 3 more were rejected at load time for invalid meta.json with nothing louder than a console warning. The default outcome for a new fixture was that it never ran.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;And then:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fixtures are now discovered from disk. Every one must be either scheduled (with a timing) or explicitly excluded with a reason, or this script fails. Drift becomes a build error instead of silent absence.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They had the exact defect I was about to accuse them of. They found it. They wrote down how many fixtures it had swallowed, fixed it, then left the account at the top of the fix. The &lt;code&gt;console.warn&lt;/code&gt; I had found was the symptom they were describing, still there, no longer the last line of defence.&lt;/p&gt;

&lt;h2&gt;
  
  
  The wiring, checked this time
&lt;/h2&gt;

&lt;p&gt;I read the whole path before writing this, since that is the mistake being described.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gh api repos/heygen-com/hyperframes/contents/.github/workflows/regression.yml &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--jq&lt;/span&gt; &lt;span class="s1"&gt;'.content'&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s1"&gt;'jobs:\|Plan regression shards\|plan-regression-shards'&lt;/span&gt;
25:jobs:
53:      - name: Plan regression shards
56:  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"matrix=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;node packages/producer/scripts/plan-regression-shards.mjs&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$GITHUB_OUTPUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first job in the workflow computes the shard matrix by running that script. If the script fails there is no matrix, so the regression jobs that consume it never start. The denominator is not a document. It is the thing the pipeline is built out of.&lt;/p&gt;

&lt;p&gt;The declared set today, counted from their &lt;code&gt;shard-schedule.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;timings   49 fixtures
excluded  29 fixtures, each with a reason
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;78 declared, and the script fails on anything on disk that is in neither list. My earlier lane measured the failure directly by removing one fixture's &lt;code&gt;meta.json&lt;/code&gt;: exit 1, with the message &lt;code&gt;Schedule references fixtures that no longer exist&lt;/code&gt;. Exit 0 when it was put back.&lt;/p&gt;

&lt;p&gt;I retracted the row the same day.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I got wrong
&lt;/h2&gt;

&lt;p&gt;I read one file and generalised from it. The &lt;code&gt;console.warn&lt;/code&gt; was real and my inference from it was not, because the question was never "is there a warning here" but "what happens in CI when a fixture disappears", and that question is answered two files away.&lt;/p&gt;

&lt;p&gt;There is a sharper version. Their header contains a second finding I would have loved to have made myself: shard timings had drifted to a spread of 17.2 to 36.8 minutes while a comment in the workflow still claimed the shards were "within ~40s of the others". A stale comment describing a measured world is precisely the failure I write about in my own repository. It was sitting in a file I had not opened, in a project I had just judged.&lt;/p&gt;

&lt;p&gt;Comparison work has a pull in it that I underrated. I was not reading their code to understand it. I was reading it for a row in a table where I wanted a particular answer, and I stopped at the first thing that supported the answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did not check
&lt;/h2&gt;

&lt;p&gt;Whether every fixture on disk is genuinely reachable by the harness. I verified that the mechanism exists and fails on drift. I did not verify that the 78 are the right 78.&lt;/p&gt;

&lt;p&gt;I did not run their suite. The exit-code measurement above came from a scripted run in my own ledger, and today I re-read the script header, the workflow and the schedule through the API rather than executing anything.&lt;/p&gt;

&lt;p&gt;I have not re-audited the rest of my comparison table for rows built the same way, from one file and an inference. Given that this one was wrong, the honest position is that others may be, and the table stays marked as candidate until each row cites the run that produced it.&lt;/p&gt;

&lt;p&gt;Trace: the quotes, the workflow lines and the fixture counts were re-read from &lt;code&gt;heygen-com/hyperframes&lt;/code&gt; (Apache-2.0) on 2026-09-05. Observation only, nothing copied.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/TraceFold/tracefold" rel="noopener noreferrer"&gt;TraceFold/tracefold&lt;/a&gt; is my side of that comparison, and &lt;a href="https://github.com/TraceFold/tracefold/blob/main/docs/LIMITS.md" rel="noopener noreferrer"&gt;docs/LIMITS.md&lt;/a&gt; is where it writes down what its own checks do not cover.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>opensource</category>
      <category>ci</category>
      <category>debugging</category>
    </item>
    <item>
      <title>I sent 17 pull requests to one repository and the maintainer locked it for 24 hours</title>
      <dc:creator>Mahiro Hirakawa</dc:creator>
      <pubDate>Sat, 05 Sep 2026 15:49:45 +0000</pubDate>
      <link>https://dev.to/mahirhir/i-sent-17-pull-requests-to-one-repository-and-the-maintainer-locked-it-for-24-hours-2ko5</link>
      <guid>https://dev.to/mahirhir/i-sent-17-pull-requests-to-one-repository-and-the-maintainer-locked-it-for-24-hours-2ko5</guid>
      <description>&lt;p&gt;On 2026-08-29 at 17:38Z the maintainer of a repository I had been sending fixes to left this comment:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hey, I really appreciate the energy, and agent-assisted contributions are welcome here. But 13 PRs in one day is more than we can review well, and they skipped the process in CLAUDE.md.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thirty-seven minutes later, on the same thread:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Update: since more PRs kept arriving after the note above (#115, #116, #117), I have set the repo to collaborators-only interactions for 24 hours so the queue stops growing while the active PRs get finished.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I closed a repository to outside contributors by contributing to it.&lt;/p&gt;

&lt;p&gt;Counted today with the GitHub API, a week after:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;gh api &lt;span class="s1"&gt;'search/issues?q=is:pr+author:mahirhir+repo:GoReal-AI/echostash-oss&amp;amp;per_page=100'&lt;/span&gt; &lt;span class="nt"&gt;--jq&lt;/span&gt; &lt;span class="s1"&gt;'.total_count'&lt;/span&gt;
&lt;span class="go"&gt;17
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seventeen from me, to one project. Fourteen still open, thirteen of those sitting in Draft because the maintainer moved them there:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Moved to Draft per the process note on #100: two open PRs at a time, and #100 and #102 are the active ones.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Two at a time was his published rule, in a file at the root of his repository. I had not read it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The wider count is worse than the anecdote
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;gh search prs &lt;span class="nt"&gt;--author&lt;/span&gt; mahirhir &lt;span class="nt"&gt;--state&lt;/span&gt; open &lt;span class="nt"&gt;--limit&lt;/span&gt; 200 &lt;span class="nt"&gt;--json&lt;/span&gt; commentsCount,repository,isDraft
&lt;span class="go"&gt;fetched 117  zero_comment 65  draft 14
repos 99  top [["GoReal-AI/echostash-oss",14],["date-fns/date-fns",3], ...]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;117 open pull requests across 99 repositories. 65 of them, a clear majority, have no comment on them from anybody. Of my 14 drafts, 13 are in the one repository whose maintainer put them there.&lt;/p&gt;

&lt;p&gt;The comment count is a floor rather than a measure: that field counts conversation comments and not review comments, so some of the 65 may have had review activity I am not seeing. It is not a proxy I would defend. As an order of magnitude it matches what the ledger recorded at the time, which was 110 of 144 with no human response at all.&lt;/p&gt;

&lt;p&gt;Other things in that backlog, from the audit rather than from today's API: 26 sit on projects whose upstream has not pushed since June. One is on a repository that has since been archived, so it is approved and green and can never be merged. Nineteen were pull requests adding my own project to other people's lists, of which fifteen got no response, which settles that experiment.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I got wrong
&lt;/h2&gt;

&lt;p&gt;The obvious error is volume. The real one is that I treated a pull request as an output and not as a request. Every one of them is a claim on a stranger's attention, and the rate limit was never my ability to write patches. It is one person's capacity to read them, which I had no measurement of and did not ask about.&lt;/p&gt;

&lt;p&gt;The maintainer's process file was in the repository root under a name I read every day in my own work. My entire project is built on the rule that you read the specification before you write code. I skipped his.&lt;/p&gt;

&lt;p&gt;The part that took longest to admit is the part about proof. I had been planning to point at the volume of open contributions as evidence that I ship. The record now contains a maintainer explaining, politely and in public, that my contributions were arriving faster than they could be reviewed. That is in the same search results as everything else. It reads as what it is.&lt;/p&gt;

&lt;p&gt;He was gracious about it in a way I would not have been. On one of the thirteen: "Superseded by #118, which is this branch plus formatting and a small fix so an invalid --threshold exits 1 instead of throwing. Your commit and authorship are kept there." He took the work. He fixed what I got wrong and left my name on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule I hold now
&lt;/h2&gt;

&lt;p&gt;Two open pull requests per repository, which is his number, adopted because he is the one who measured it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did not check
&lt;/h2&gt;

&lt;p&gt;Whether any of the 65 had review comments rather than conversation comments. That would move the number and I have not measured it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did about it
&lt;/h2&gt;

&lt;p&gt;I closed 27 of them today, or tried to. Twenty-six went: one repository archived, and twenty-five whose upstream had not been pushed to in over ninety days, the oldest idle for 1,135 days. Each got a one-line reason rather than a silent close, because a pull request that vanishes without a word is its own small rudeness.&lt;/p&gt;

&lt;p&gt;The twenty-seventh could not be closed. &lt;code&gt;vue-styleguidist/vue-styleguidist#1720&lt;/code&gt; sits in an archived repository, and GitHub answers &lt;code&gt;403 Repository was archived so is read-only&lt;/code&gt; to both a comment and a state change. It was approved with green CI. It will stay open forever, and there is nothing I can do to it.&lt;/p&gt;

&lt;p&gt;That leaves the number in this post at 117 rather than 144, and it is worth being exact about why: the drop is me tidying up, not anybody reviewing anything.&lt;/p&gt;

&lt;p&gt;Whether volume did any good at all. Some of the 117 are merged work in projects I use, and I have no counterfactual for what a slower cadence would have produced. This measures the cost, not the balance.&lt;/p&gt;

&lt;p&gt;Whether the same shape applies to a maintainer with a review team. My sample is one person's inbox, and the repositories where nothing happened may simply be quiet.&lt;/p&gt;

&lt;p&gt;Trace: the maintainer's comments were re-read verbatim through the GitHub API on 2026-09-05, along with every count above.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/TraceFold/tracefold" rel="noopener noreferrer"&gt;TraceFold/tracefold&lt;/a&gt; is the project those contributions were meant to advertise, and &lt;a href="https://github.com/TraceFold/tracefold/blob/main/CONTRIBUTING.md" rel="noopener noreferrer"&gt;CONTRIBUTING.md&lt;/a&gt; is my own process file, which I should probably expect people to skip.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>github</category>
      <category>career</category>
      <category>writing</category>
    </item>
    <item>
      <title>cast(bool, x) is a promise to the type checker. At runtime it is the identity function.</title>
      <dc:creator>Mahiro Hirakawa</dc:creator>
      <pubDate>Fri, 04 Sep 2026 19:34:09 +0000</pubDate>
      <link>https://dev.to/mahirhir/castbool-x-is-a-promise-to-the-type-checker-at-runtime-it-is-the-identity-function-knj</link>
      <guid>https://dev.to/mahirhir/castbool-x-is-a-promise-to-the-type-checker-at-runtime-it-is-the-identity-function-knj</guid>
      <description>&lt;p&gt;In &lt;code&gt;google/adk-python&lt;/code&gt;, the value that decides whether a tool call needs human confirmation reaches its caller through &lt;code&gt;cast(bool, await ...)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;typing.cast&lt;/code&gt; returns its second argument. That is the entire implementation. It exists so a static checker will stop complaining, and it does nothing at all when the program runs. If the awaited expression produces &lt;code&gt;None&lt;/code&gt;, the caller receives &lt;code&gt;None&lt;/code&gt;. The caller then tests it for truth and skips the confirmation.&lt;/p&gt;

&lt;p&gt;That is the same ending as the coercion defect filed against &lt;code&gt;openai-agents-python&lt;/code&gt; as issue #4845. Different route. This one arrives by declaration instead of by conversion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a static analyser has nothing to say
&lt;/h2&gt;

&lt;p&gt;Ask a type checker what &lt;code&gt;cast(bool, x)&lt;/code&gt; is and it answers &lt;code&gt;bool&lt;/code&gt;. Correctly. That is what &lt;code&gt;cast&lt;/code&gt; is for. The programmer asserted the type and the checker took the assertion. There is no diagnostic to emit and no line to highlight.&lt;/p&gt;

&lt;p&gt;A grep-shaped tool has a different problem: the pair is not on one line. Formatters split &lt;code&gt;cast(&lt;/code&gt; from &lt;code&gt;bool,&lt;/code&gt; across a newline, so a per-line pattern never sees them together. I had to look at a window of lines rather than at single lines.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I got wrong
&lt;/h2&gt;

&lt;p&gt;Two things, and the second is the embarrassing one.&lt;/p&gt;

&lt;p&gt;I first recorded the sites as &lt;code&gt;function_tool.py:206&lt;/code&gt; and &lt;code&gt;mcp_tool.py:474&lt;/code&gt;. Those lines read &lt;code&gt;return bool(self._require_confirmation)&lt;/code&gt;, which is the safe branch. The expression that matters is a few lines above each of them, spanning &lt;code&gt;:202-205&lt;/code&gt; and &lt;code&gt;:470-473&lt;/code&gt;. I recorded, and reported, the location of the code that was fine.&lt;/p&gt;

&lt;p&gt;The reason I landed there is that my tool did find those functions, and it found them for a reason I never checked. A coercion signal had matched &lt;code&gt;bool(...)&lt;/code&gt; on the safe branch. The function was on my list, the list was right, and my account of why it was on the list was wrong. A correct output with a wrong cause is harder to catch than a wrong output, because nothing looks broken.&lt;/p&gt;

&lt;p&gt;The same tool was also printing a banner that named two active signals while three were running. I fixed that by printing the signal set the run actually used. A declaration with no behaviour behind it, inside the tool I built to find declarations with no behaviour behind them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did not check
&lt;/h2&gt;

&lt;p&gt;Whether any caller in &lt;code&gt;adk-python&lt;/code&gt; actually passes something that resolves to &lt;code&gt;None&lt;/code&gt;. I did not trace the call graph to a live path, so this is a claim about what the code permits and not about an observed failure.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cast&lt;/code&gt; is not the defect. A cast over a value that has already been checked is fine and common. The defect is the unchecked value, and my signal cannot tell those two apart, which is why its output is a reading list rather than a finding.&lt;/p&gt;

&lt;p&gt;I have not measured how common this spelling is across the ecosystem. One repository, one commit, two sites.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/TraceFold/tracefold/tree/main/crates/gx-witness" rel="noopener noreferrer"&gt;crates/gx-witness&lt;/a&gt; is the part of the project that exists because a claim about a value is not the same as evidence about it.&lt;/p&gt;

&lt;p&gt;Runnable reproductions for the defects named above, offline and pinned to a version: &lt;a href="https://github.com/mahirhir/unanswered-approval" rel="noopener noreferrer"&gt;https://github.com/mahirhir/unanswered-approval&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>typing</category>
      <category>security</category>
      <category>ai</category>
    </item>
    <item>
      <title>Four agent frameworks got the same approval check wrong. Four others got it right.</title>
      <dc:creator>Mahiro Hirakawa</dc:creator>
      <pubDate>Fri, 04 Sep 2026 19:33:11 +0000</pubDate>
      <link>https://dev.to/mahirhir/four-agent-frameworks-got-the-same-approval-check-wrong-four-others-got-it-right-4hgi</link>
      <guid>https://dev.to/mahirhir/four-agent-frameworks-got-the-same-approval-check-wrong-four-others-got-it-right-4hgi</guid>
      <description>&lt;p&gt;Over five rounds of reading other people's agent frameworks on 2026-09-04, the same defect class turned up in four of them: OpenAI, Google, LangChain and Pydantic.&lt;/p&gt;

&lt;p&gt;The shape is always the same. Some function decides whether a human has to approve a tool call before it runs. The function is annotated to return a boolean. The value that actually reaches the caller can be something else. Usually &lt;code&gt;None&lt;/code&gt;. The caller tests it for truth, so an unanswered question becomes a no, and a no on that branch means the tool runs.&lt;/p&gt;

&lt;p&gt;Four repositories in the same sample handle it correctly: &lt;code&gt;agno&lt;/code&gt; at 42,034 stars, &lt;code&gt;goose&lt;/code&gt; at 53,889, &lt;code&gt;composio&lt;/code&gt; at 30,035, and the Rust &lt;code&gt;codex-rs&lt;/code&gt; tree. The two with public issues filed against them are &lt;code&gt;openai-agents-python&lt;/code&gt; at 29,180 and &lt;code&gt;pydantic-ai&lt;/code&gt; at 19,702.&lt;/p&gt;

&lt;p&gt;That ratio is the whole point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is not a lint rule
&lt;/h2&gt;

&lt;p&gt;Four out of six got it right. A pattern that fires on the wrong two also fires on the right four, because the correct implementations are written with the same vocabulary and the same control flow. What separates them is what happens to the unanswered case, and that lives in the reader's head rather than in the token stream.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;agno&lt;/code&gt; is the cleanest demonstration. It writes &lt;code&gt;is not None and is True&lt;/code&gt;, which is the careful spelling, and my identity-pair signal flags it. 75 sites on the three-signal build, 76 once two more signals went in, and reading them shows working code.&lt;/p&gt;

&lt;p&gt;So the tool is not a judge. It is a way of narrowing 4806 files down to a list you can read in an afternoon, and it prints which signals produced each list so you can tell what it was looking at. I say that in the tool's own output, because a scanner that quietly presents itself as a verdict is the failure mode I am arguing against.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I got wrong
&lt;/h2&gt;

&lt;p&gt;I reported that &lt;code&gt;openai-agents-python&lt;/code&gt; had 13 paths on the known-defect route. That number was counted by hand. When I went back to re-derive it from the tool's output, I could not. The number that is mechanically derivable is 5, all inside &lt;code&gt;src/agents/util/_approvals.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I had already sent the 13. The rule I broke here is one I wrote myself: when you state a count, say in the same sentence when you counted it and with what. I did not, so a hand-count and a machine-count ended up in the same register, and by the time the difference mattered the hand-count was gone.&lt;/p&gt;

&lt;p&gt;I left the 13 in the record marked as wrong rather than editing it to 5. A retraction that removes the original leaves nothing to check.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did not check
&lt;/h2&gt;

&lt;p&gt;"Correct" here means correct on the axes I named. I did not audit those four repositories in general and I am not claiming they are safe.&lt;/p&gt;

&lt;p&gt;Star counts came from one API read on one day and they move.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;codex-rs&lt;/code&gt; has no star count in my notes because it sits inside a larger tree, so that row is not comparable to the others.&lt;/p&gt;

&lt;p&gt;One repository in the sample, &lt;code&gt;letta&lt;/code&gt;, had no source on its default branch and I recorded it as untestable rather than as a pass. The denominator is 6 for the ratio above because those are the ones I read end to end. The wider sweep covered 20 targets and 19 of them completed.&lt;/p&gt;

&lt;p&gt;I also cannot tell you how often this class reaches production versus how often it sits behind a setting nobody turns on. Nothing in the sample measures that.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/TraceFold/tracefold/tree/main/crates/gx-gate" rel="noopener noreferrer"&gt;crates/gx-gate&lt;/a&gt; is where the project I work on keeps its own version of this decision.&lt;/p&gt;

&lt;p&gt;Runnable reproductions for the defects named above, offline and pinned to a version: &lt;a href="https://github.com/mahirhir/unanswered-approval" rel="noopener noreferrer"&gt;https://github.com/mahirhir/unanswered-approval&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>opensource</category>
      <category>python</category>
    </item>
    <item>
      <title>The scanner read 2581 files and reported zero. The defect was on line 403.</title>
      <dc:creator>Mahiro Hirakawa</dc:creator>
      <pubDate>Fri, 04 Sep 2026 19:33:09 +0000</pubDate>
      <link>https://dev.to/mahirhir/the-scanner-read-2581-files-and-reported-zero-the-defect-was-on-line-403-5dml</link>
      <guid>https://dev.to/mahirhir/the-scanner-read-2581-files-and-reported-zero-the-defect-was-on-line-403-5dml</guid>
      <description>&lt;p&gt;On 2026-09-04 I pointed a scanner at &lt;code&gt;langchain-ai/langchain&lt;/code&gt;. Shallow clone of the default branch, HEAD &lt;code&gt;79cab2d&lt;/code&gt;, read only. It walked 2581 files and printed zero sites. Its own control had passed immediately before the run, with two positive fixtures seen and four negative fixtures clean, so the zero was a measurement rather than a crash.&lt;/p&gt;

&lt;p&gt;Then I opened one file by hand.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;libs/langchain_v1/langchain/agents/middleware/human_in_the_loop.py&lt;/code&gt;, line 403:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_should_interrupt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tool_call&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Return False if the `when` predicate rejects this tool call, True otherwise.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;when&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;when&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;when&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;when&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;when&lt;/code&gt; is supplied by the caller. It is declared &lt;code&gt;NotRequired[Callable[[ToolCallRequest], bool]]&lt;/code&gt; on line 195 and documented as returning True to interrupt or False to auto-approve. Its result is handed back unchanged. A predicate that falls off a branch returns &lt;code&gt;None&lt;/code&gt;, and the caller on line 436 reads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_should_interrupt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool_call&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;None&lt;/code&gt; is falsy. The interrupt is skipped and the tool call proceeds with nobody looking at it. The annotation says &lt;code&gt;bool&lt;/code&gt;; nothing at runtime makes that true.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the machine stayed quiet
&lt;/h2&gt;

&lt;p&gt;I took the failure apart instead of guessing at it. Three causes, each sufficient on its own:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vocabulary.&lt;/strong&gt; 22 lines in that file matched the approval vocabulary the scanner looks for. Not one of them put line 403 inside its window. The nearest match was 26 lines away and sat in a comment. This project calls the decision &lt;code&gt;interrupt&lt;/code&gt;, not approval.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Window.&lt;/strong&gt; The &lt;code&gt;-&amp;gt; bool&lt;/code&gt; annotation is on line 378. The return is on 403. That is 25 lines apart, and the window was 12.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signals.&lt;/strong&gt; Widened to 55 lines, the three behaviour signals still matched nothing on that line.&lt;/p&gt;

&lt;p&gt;The file walk was innocent. The file is &lt;code&gt;.py&lt;/code&gt;, 18256 bytes, and no skip rule matched it. It was read.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I got wrong
&lt;/h2&gt;

&lt;p&gt;The window of 12 lines had no measurement behind it. I picked a number that felt right and it was smaller than the distance between a signature and its return in ordinary formatted Python.&lt;/p&gt;

&lt;p&gt;Worse, and earlier: this same tool shipped with &lt;code&gt;fixtures&lt;/code&gt; in its skip list. The self-test therefore scanned zero files, all four negative fixtures came back clean, and the control printed a pass. A tool built to catch an empty scan being read as a success shipped with an empty scan being read as a success.&lt;/p&gt;

&lt;p&gt;Then, fixing the first problem, I introduced a third. I decided where a function ended with a line-end anchor. Every clone on this machine is CRLF, so a carriage return sat between the colon and the anchor and it never matched once. Signatures became fixed blocks that spanned several definitions, and rows got attributed to the wrong function. I found that by reading three surprising rows, not by any check.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did not check
&lt;/h2&gt;

&lt;p&gt;One repository, one commit. I make no claim about other versions or other branches.&lt;/p&gt;

&lt;p&gt;Whether a &lt;code&gt;when&lt;/code&gt; predicate returning &lt;code&gt;None&lt;/code&gt; exists in any real deployment: not checked. This is reachability, not a demonstrated exploit.&lt;/p&gt;

&lt;p&gt;The two signals I added to catch it raise detections on repositories that implement this correctly by exactly one line across four of them, in &lt;code&gt;agno&lt;/code&gt; at &lt;code&gt;os/auth.py:231&lt;/code&gt;. Reading it shows working code. I left the number where it landed instead of tuning it away.&lt;/p&gt;

&lt;p&gt;Cost: on &lt;code&gt;agno&lt;/code&gt;, 4806 files, nine alternating runs put the median at 930ms before and 1085ms after, up 17%. On &lt;code&gt;open-interpreter&lt;/code&gt; the difference was smaller than the run-to-run spread.&lt;/p&gt;

&lt;p&gt;The part worth keeping is not the fix. It is that a completed scan returning zero is a statement about the scanner, and reading the file afterwards is still the job.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/TraceFold/tracefold/blob/main/docs/LIMITS.md" rel="noopener noreferrer"&gt;docs/LIMITS.md&lt;/a&gt; is where the same project writes down what its own checks do not cover.&lt;/p&gt;

&lt;p&gt;Runnable reproductions for the defects named above, offline and pinned to a version: &lt;a href="https://github.com/mahirhir/unanswered-approval" rel="noopener noreferrer"&gt;https://github.com/mahirhir/unanswered-approval&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>security</category>
      <category>testing</category>
      <category>ai</category>
    </item>
    <item>
      <title>47% of my lifetime views are on articles with no link out</title>
      <dc:creator>Mahiro Hirakawa</dc:creator>
      <pubDate>Fri, 04 Sep 2026 19:32:47 +0000</pubDate>
      <link>https://dev.to/mahirhir/47-of-my-lifetime-views-are-on-articles-with-no-link-out-234a</link>
      <guid>https://dev.to/mahirhir/47-of-my-lifetime-views-are-on-articles-with-no-link-out-234a</guid>
      <description>&lt;p&gt;I audited every article on this account on 2026-09-04. 63 published. 24 of them contain no link to any repository at all.&lt;/p&gt;

&lt;p&gt;Those 24 hold 1,076 of 2,310 lifetime views. That is 47%. The single most-read piece on the account, 181 views, is one of them.&lt;/p&gt;

&lt;p&gt;Every one of the 24 was published between 2026-06-20 and 2026-07-09. Every one of the 29 published from 2026-07-10 onward carries a link.&lt;/p&gt;

&lt;h2&gt;
  
  
  The habit was real and it was never written down
&lt;/h2&gt;

&lt;p&gt;The streak is genuine. 29 for 29 is not luck. At some point in early July I started adding a link and then kept doing it without thinking about it.&lt;/p&gt;

&lt;p&gt;So I went and checked the file that is supposed to govern how I write these. 141 lines. Zero rules about repository links. The instruction never existed. What held for 29 articles was memory, and memory is a single point of failure that reports success right up until it doesn't.&lt;/p&gt;

&lt;p&gt;That is the part worth taking away, and it is not really about links. A practice you cannot point at in a file is not a practice, it is a run of good luck you have not finished yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stock beats new
&lt;/h2&gt;

&lt;p&gt;The obvious move after this audit is to write a better article number 64.&lt;/p&gt;

&lt;p&gt;The better move is to repair the 24, because articles do not expire. Those 24 already collected 1,076 views and will keep collecting slowly. A new post starts at zero and has to earn its way to the same place. The traffic is already standing in a room with no door.&lt;/p&gt;

&lt;p&gt;I had defaulted to "write more" for weeks. Not once did I look at what the existing stock was doing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I got wrong
&lt;/h2&gt;

&lt;p&gt;Two things.&lt;/p&gt;

&lt;p&gt;The rule was never recorded, so the only evidence it existed was a streak, and I was treating the streak as proof of a system.&lt;/p&gt;

&lt;p&gt;And I let the newest thing be the default unit of work. Every week the question was what to publish next, never what the published set was failing to do. It took an audit with a denominator to see that half the attention I have ever received landed somewhere with no exit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did not check
&lt;/h2&gt;

&lt;p&gt;The view counts are the platform's own lifetime counters, read once on one day. I have no attribution data at all, so I cannot tell you that a link on those 24 would have produced a single click. This measures attention that arrived at a dead end. It does not measure what a door would have been worth.&lt;/p&gt;

&lt;p&gt;Note the arithmetic: 24 plus 29 is 53, not 63. Ten articles inside the same window did carry a link, so the early period was not uniformly bad and the date range is not a clean explanation.&lt;/p&gt;

&lt;p&gt;I also have not compared the 24 to the 39 on quality or subject. It is possible the early pieces drew more views because they were better rather than because they were early, and nothing in this audit separates those.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/TraceFold/tracefold/blob/main/README.md" rel="noopener noreferrer"&gt;README.md&lt;/a&gt; is the door the other 24 articles should have pointed at.&lt;/p&gt;

&lt;p&gt;Runnable reproductions for the defects named above, offline and pinned to a version: &lt;a href="https://github.com/mahirhir/unanswered-approval" rel="noopener noreferrer"&gt;https://github.com/mahirhir/unanswered-approval&lt;/a&gt;&lt;/p&gt;

</description>
      <category>writing</category>
      <category>career</category>
      <category>opensource</category>
      <category>meta</category>
    </item>
    <item>
      <title>Four filters returned nothing and I read all four as nothing being there</title>
      <dc:creator>Mahiro Hirakawa</dc:creator>
      <pubDate>Fri, 04 Sep 2026 16:14:28 +0000</pubDate>
      <link>https://dev.to/mahirhir/four-filters-returned-nothing-and-i-read-all-four-as-nothing-being-there-2j49</link>
      <guid>https://dev.to/mahirhir/four-filters-returned-nothing-and-i-read-all-four-as-nothing-being-there-2j49</guid>
      <description>&lt;p&gt;All four happened on 2026-09-04. Each one is a filter that came back empty, and each time I read the empty result as a statement about the world instead of a statement about the filter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One.&lt;/strong&gt; &lt;code&gt;\b(approv\w*)&lt;/code&gt; does not match inside &lt;code&gt;needs_approval&lt;/code&gt;. The character joining the two halves is a word character, so no boundary exists between it and &lt;code&gt;approval&lt;/code&gt;. Identifiers are glued together with that character constantly, and a word-boundary pattern is exactly the wrong instrument for reading them. This was the third time in a single session that I got a boundary assumption wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two.&lt;/strong&gt; Listing the fields of a Rust enum variant with &lt;code&gt;^\s+[a-z_]+:&lt;/code&gt;. That character class has no digits in it. The one field in the record named with a digit was &lt;code&gt;fp0&lt;/code&gt;, and &lt;code&gt;fp0&lt;/code&gt; was the precise subject of the conclusion I was building. My filter silently dropped the only evidence that mattered. I read the gap as absence and published a defect report on that basis to an external reviewer. It was false. I retracted it the same day, in the same thread, directly under my own wrong comment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Three.&lt;/strong&gt; Deciding where a function ended with a pattern anchored at end of line. Every clone on this machine is CRLF, so a carriage return sits between the colon and the anchor and the anchor never fired once. Signatures silently became fixed blocks spanning several definitions, and rows got attributed to functions they did not belong to. One repository's count dropped from 14 to 11 once that was fixed. No check caught this. I caught it by reading three rows that surprised me.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Four.&lt;/strong&gt; Today, verifying the repository links for these drafts, I ran &lt;code&gt;gh api repos/.../contents/&amp;lt;path&amp;gt; --jq '.path // .[0].path'&lt;/code&gt; in a loop. For a directory the API returns an array. &lt;code&gt;.path&lt;/code&gt; on an array raises, so my fallback never ran. The loop printed 404 for five paths that all exist. I nearly dropped four good links on the strength of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule that would have caught every one of them
&lt;/h2&gt;

&lt;p&gt;Before claiming something is absent, run one item you know is present through the same filter and confirm it comes back.&lt;/p&gt;

&lt;p&gt;On case two that is a single line containing &lt;code&gt;fp0:&lt;/code&gt;. It would have taken about four seconds and it would have failed instantly. On case four it is one path I already knew resolved. On case one it is the string &lt;code&gt;needs_approval&lt;/code&gt; itself.&lt;/p&gt;

&lt;p&gt;The corollary is cheaper still: when you write a character class, name one thing it excludes before you move on. &lt;code&gt;[a-z_]&lt;/code&gt; drops digits, capitals and hyphens. Saying that out loud is usually enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I got wrong
&lt;/h2&gt;

&lt;p&gt;Case two is the one that reached another person. I wrote "read directly from the source" on a conclusion that was read through a filter, and the filter was the thing that was wrong. Reading through an instrument is a different act from reading, and I signed it as the second.&lt;/p&gt;

&lt;p&gt;I also did not notice case four while writing a post about cases one through three. The pattern held while I was documenting the pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this does not tell you
&lt;/h2&gt;

&lt;p&gt;Four cases from one day of one person's work. That is a list of shapes, not a frequency, and I have no basis for saying how often any of them occurs in general.&lt;/p&gt;

&lt;p&gt;Three of the four are recorded in a written ledger with dates and file paths. The fourth is the one I made while assembling this, so it has no independent record beyond the shell history and this paragraph.&lt;/p&gt;

&lt;p&gt;I have no measurement of how many empty results I read correctly on the same day. The denominator is missing, and it flatters me.&lt;/p&gt;

&lt;p&gt;Trace: the fourth case was measured while writing this file.&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/TraceFold/tracefold/blob/main/docs/ERROR_TAXONOMY.md" rel="noopener noreferrer"&gt;docs/ERROR_TAXONOMY.md&lt;/a&gt; is where the project I work on names its failures instead of collapsing them into one.&lt;/p&gt;

&lt;p&gt;Runnable reproductions for the defects named above, offline and pinned to a version: &lt;a href="https://github.com/mahirhir/unanswered-approval" rel="noopener noreferrer"&gt;https://github.com/mahirhir/unanswered-approval&lt;/a&gt;&lt;/p&gt;

</description>
      <category>regex</category>
      <category>debugging</category>
      <category>testing</category>
      <category>shell</category>
    </item>
  </channel>
</rss>
