<?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: Blake Yang</title>
    <description>The latest articles on DEV Community by Blake Yang (@datars_7274).</description>
    <link>https://dev.to/datars_7274</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%2F4061230%2F081cb59c-26d8-46fd-a592-ce04b6639b4b.png</url>
      <title>DEV Community: Blake Yang</title>
      <link>https://dev.to/datars_7274</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/datars_7274"/>
    <language>en</language>
    <item>
      <title>Ship an OSS Patch With a Reviewer Question Bank, Not Just a Diff</title>
      <dc:creator>Blake Yang</dc:creator>
      <pubDate>Mon, 21 Sep 2026 12:46:43 +0000</pubDate>
      <link>https://dev.to/datars_7274/ship-an-oss-patch-with-a-reviewer-question-bank-not-just-a-diff-3ag0</link>
      <guid>https://dev.to/datars_7274/ship-an-oss-patch-with-a-reviewer-question-bank-not-just-a-diff-3ag0</guid>
      <description>&lt;p&gt;A maintainer opened the crash-fix pull request after a long triage shift and found a three-line diff with no reproduction notes. The commit message claimed the parser no longer panicked, yet the issue still lacked a failing command for a clean checkout. Review time vanished into guesswork about callers, error paths, and whether the public API still returned the same sentinel values. The tab closed, and the contributor waited three days for a review that never started.&lt;/p&gt;

&lt;p&gt;That stall is rarely about missing brilliance in the patch, and it is almost never about git hygiene alone. Maintainers ration attention across many repositories, and an unexplained diff is expensive even when the change is correct. Contributors who used a coding model to draft the hunks often ship fluent code that still fails the social contract of review. The missing artifact is not more commentary in the PR template; it is a question bank the contributor already answered.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unexplained diffs stall because review is interrogation
&lt;/h2&gt;

&lt;p&gt;Open-source review is a time-boxed interrogation, not a rubber stamp on a green CI badge. A careful reviewer still needs the reproduction, the moved public symbols, and the error paths that must keep failing. Those demands appear whether or not the contributor writes them down in advance of the request. Writing them first turns the pull request into evidence instead of a riddle wrapped in a unified diff.&lt;/p&gt;

&lt;p&gt;Most contribution templates ask for a summary, a test plan, and a checklist of boxes. Those boxes age into ritual, and they do not change when the diff touches an exported error type. A question bank is generated from this branch's paths, headers, and exit codes, so the questions track the patch. The template in &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; can stay generic while the bank stays specific to the branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  The artifact: REVIEWER_QUESTIONS.md
&lt;/h2&gt;

&lt;p&gt;The proposed artifact is a single Markdown file named &lt;code&gt;REVIEWER_QUESTIONS.md&lt;/code&gt; that lives beside the patch branch. Each entry is a maintainer question, a required evidence pointer, and a short answer that cites a file and line. Unanswered items remain marked &lt;code&gt;TODO&lt;/code&gt; so a local gate can refuse to open the pull request. The file is not a blog post and should stay short enough to read in about twelve minutes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Reviewer Question Bank&lt;/span&gt;

Project: example-parser
Issue: https://github.com/example/parser/issues/1842
Branch: fix/issue-1842
Base: origin/main

&lt;span class="gu"&gt;## Q1. Reproduction&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Question: What single command fails on a clean checkout of main and passes on this branch?
&lt;span class="p"&gt;-&lt;/span&gt; Evidence: TODO
&lt;span class="p"&gt;-&lt;/span&gt; Answer: TODO

&lt;span class="gu"&gt;## Q2. Public surface&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Question: Which exported symbols changed name, type, or error contract?
&lt;span class="p"&gt;-&lt;/span&gt; Evidence: TODO
&lt;span class="p"&gt;-&lt;/span&gt; Answer: TODO

&lt;span class="gu"&gt;## Q3. Negative path&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Question: Which input must still fail, and what exit code is preserved?
&lt;span class="p"&gt;-&lt;/span&gt; Evidence: TODO
&lt;span class="p"&gt;-&lt;/span&gt; Answer: TODO

&lt;span class="gu"&gt;## Q4. Regression test&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Question: Where is the test that would have failed before the patch?
&lt;span class="p"&gt;-&lt;/span&gt; Evidence: TODO
&lt;span class="p"&gt;-&lt;/span&gt; Answer: TODO

&lt;span class="gu"&gt;## Q5. Commit shape&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Question: Does each commit encode one logical change a revert could isolate?
&lt;span class="p"&gt;-&lt;/span&gt; Evidence: TODO
&lt;span class="p"&gt;-&lt;/span&gt; Answer: TODO

&lt;span class="gu"&gt;## Q6. Docs and changelog&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Question: What user-visible behavior needs a changelog note, or why is none required?
&lt;span class="p"&gt;-&lt;/span&gt; Evidence: TODO
&lt;span class="p"&gt;-&lt;/span&gt; Answer: TODO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Six steps from a failing command to a fail-closed gate
&lt;/h2&gt;

&lt;p&gt;The following workflow is a proposed local checklist, and the commands are illustrative rather than a recorded run against a public crate. Contributors should swap the binary names, fixture paths, and test runners for the project under patch. The point of the checklist is the review packet rather than any particular language or CI toolchain.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Freeze the failing command
&lt;/h3&gt;

&lt;p&gt;Before any edit, record one command that fails on a clean checkout of the upstream default branch. Store that command in the question bank under reproduction so later answers cannot drift into a private setup. If the crash needs a fixture, check the fixture into the branch rather than describing it in prose. Reviewers should be able to paste the command without guessing at environment variables or hidden data files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git fetch origin
git switch &lt;span class="nt"&gt;-c&lt;/span&gt; fix/issue-1842 origin/main
&lt;span class="c"&gt;# Proposed: capture the failing invocation, not a narrative.&lt;/span&gt;
./target/debug/tool parse tests/fixtures/issue-1842.json
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"expected non-zero on main"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Keep every hunk load-bearing
&lt;/h3&gt;

&lt;p&gt;Edit only the symbols required to make that command pass, and resist drive-by cleanups that enlarge the review surface. A question bank cannot rescue a diff that also reformats a neighboring module or renames an unrelated helper. Split formatting and refactors into separate pull requests if the project will accept them at all. The bank should list every touched path so a maintainer can see the blast without running extra git archaeology.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff &lt;span class="nt"&gt;--name-only&lt;/span&gt; origin/main...HEAD
git diff &lt;span class="nt"&gt;--stat&lt;/span&gt; origin/main...HEAD
git log &lt;span class="nt"&gt;--oneline&lt;/span&gt; origin/main..HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Collect exit codes instead of vibe screenshots
&lt;/h3&gt;

&lt;p&gt;Run the original failing command, the nearest unit tests, and one negative path that should still error after the fix. Capture the exit codes and a one-line summary rather than pasting entire logs into the pull request body. The question bank needs those exit codes as answers, not as decorative terminal screenshots that hide the command. Label any unexecuted matrix as proposed so a maintainer does not treat a wish as a result.&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="c"&gt;# Proposed local evidence, not a claimed CI run.&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; +e
./target/debug/tool parse tests/fixtures/issue-1842.json
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"repro_exit=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
cargo &lt;span class="nb"&gt;test &lt;/span&gt;parse_issue_1842 &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--nocapture&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"unit_exit=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
./target/debug/tool parse tests/fixtures/truncated.json
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"negative_exit=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Pack the diff and draft questions
&lt;/h3&gt;

&lt;p&gt;A coding model can draft questions from the unified diff, but it cannot invent evidence the tests never produced. Feed the model the diff, the test commands, and the project's CONTRIBUTING snippet, then keep only questions a human can answer with citations.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach. MonkeyCode's free model access can draft the bank from a unified diff, and the free server option can run the recorded test commands.&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="c"&gt;# Proposed helper: pack a small context bundle for a coding model.&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; .review-packet
git diff origin/main...HEAD &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .review-packet/patch.diff
git log &lt;span class="nt"&gt;--oneline&lt;/span&gt; origin/main..HEAD &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .review-packet/commits.txt
git diff &lt;span class="nt"&gt;--name-only&lt;/span&gt; origin/main...HEAD &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .review-packet/paths.txt
python3 scripts/list_fn_headers.py &amp;lt; .review-packet/patch.diff &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .review-packet/headers.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Proposed helper: list added and removed fn headers from a unified diff.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;added&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;removed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&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;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+++&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;---&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fn &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;added&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:].&lt;/span&gt;&lt;span class="nf"&gt;rstrip&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fn &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;removed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:].&lt;/span&gt;&lt;span class="nf"&gt;rstrip&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;## Removed headers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;removed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;- `&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;`&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;## Added headers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;added&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;- `&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;`&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;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Proposed prompt for the drafting pass, to be edited by a human before any answer is trusted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are drafting reviewer questions for an OSS patch, not writing the patch.
Read patch.diff, headers.md, and commits.txt.
Propose at most eight questions a maintainer would ask before merging.
Reject style nits. Prefer reproduction, public surface, negative paths,
tests, commit shape, and changelog impact.
Do not invent test results. Leave every Answer and Evidence as TODO.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Fill answers with file:line citations
&lt;/h3&gt;

&lt;p&gt;Each answer should be one or two sentences and must point at a path a reviewer can open. Saying tests pass is not an answer, because it hides which command and which assertion moved. If the model drafted a question the tests cannot answer, delete the question instead of fabricating a citation. A short honest bank beats a long bank that launders missing evidence behind confident, fluent prose.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Q1. Reproduction&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Question: What single command fails on a clean checkout of main and passes on this branch?
&lt;span class="p"&gt;-&lt;/span&gt; Evidence: tests/fixtures/issue-1842.json, src/parse.rs:214
&lt;span class="p"&gt;-&lt;/span&gt; Answer: &lt;span class="sb"&gt;`./target/debug/tool parse tests/fixtures/issue-1842.json`&lt;/span&gt; exited 101 on main and 0 on HEAD.

&lt;span class="gu"&gt;## Q2. Public surface&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Question: Which exported symbols changed name, type, or error contract?
&lt;span class="p"&gt;-&lt;/span&gt; Evidence: src/lib.rs:88 (still &lt;span class="sb"&gt;`pub fn parse`&lt;/span&gt;)
&lt;span class="p"&gt;-&lt;/span&gt; Answer: No exported name changed; &lt;span class="sb"&gt;`parse`&lt;/span&gt; still returns &lt;span class="sb"&gt;`Result&amp;lt;Doc, ParseError&amp;gt;`&lt;/span&gt;.

&lt;span class="gu"&gt;## Q3. Negative path&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Question: Which input must still fail, and what exit code is preserved?
&lt;span class="p"&gt;-&lt;/span&gt; Evidence: tests/fixtures/truncated.json, src/parse.rs:240
&lt;span class="p"&gt;-&lt;/span&gt; Answer: Truncated input still exits 1 with &lt;span class="sb"&gt;`ParseError::UnexpectedEof`&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Refuse to open the pull request while TODO remains
&lt;/h3&gt;

&lt;p&gt;A local gate keeps the social contract from depending on memory when the pull request is finally opened. The script below is proposed, and it only searches for the TODO markers the template uses. Contributors can wire it as a pre-push hook or as a make target named &lt;code&gt;review-packet&lt;/code&gt;. Opening the pull request then becomes a copy of the bank into the PR body, not a second writing task.&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="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# Proposed gate: refuse to open a PR while the bank still has TODO answers.&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail
&lt;span class="nv"&gt;BANK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"REVIEWER_QUESTIONS.md"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BANK&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"missing &lt;/span&gt;&lt;span class="nv"&gt;$BANK&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi
if &lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'^- (Answer|Evidence): TODO'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BANK&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"question bank is incomplete"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi
&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"question bank is complete"&lt;/span&gt;
&lt;span class="c"&gt;# Proposed: only run after the gate passes.&lt;/span&gt;
&lt;span class="c"&gt;# gh pr create --fill --body-file REVIEWER_QUESTIONS.md&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Pass rules for each required question
&lt;/h2&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;Required evidence&lt;/th&gt;
&lt;th&gt;Pass rule&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reproduction&lt;/td&gt;
&lt;td&gt;command plus exit codes&lt;/td&gt;
&lt;td&gt;Fails on &lt;code&gt;origin/main&lt;/code&gt;, passes on &lt;code&gt;HEAD&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Public surface&lt;/td&gt;
&lt;td&gt;exported names from the diff&lt;/td&gt;
&lt;td&gt;No undocumented rename or signature change&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Negative path&lt;/td&gt;
&lt;td&gt;one input that must still fail&lt;/td&gt;
&lt;td&gt;Non-zero exit and original error type preserved&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Regression test&lt;/td&gt;
&lt;td&gt;test path and assertion line&lt;/td&gt;
&lt;td&gt;Test failed before the patch and passes after&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commit shape&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git log --oneline&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;One logical change per commit, revertible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docs&lt;/td&gt;
&lt;td&gt;changelog, rustdoc, or skip reason&lt;/td&gt;
&lt;td&gt;Skip only for internal helpers with no user behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;The bank does not replace a maintainer who knows the crate's history, and it will not catch semantic bugs the tests never expressed. Models often over-generate questions about style and under-generate questions about concurrency, ABI, and platform quirks. A free server run is only as good as the command the contributor recorded in the first step. Teams that already require a formal design review should treat this file as a packet, not as a substitute for that review.&lt;/p&gt;

&lt;p&gt;Generated questions also drift when the diff includes vendored code, snapshots, or generated protobuf bindings. In those cases the header lister will emit noise, and a human should delete those rows before the drafting pass. The gate only proves that answers exist as text; it does not prove that the cited lines implement the claim. Lying in the bank is still possible, so maintainers should sample at least one citation against the working tree.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should skip this packet
&lt;/h2&gt;

&lt;p&gt;Tiny typo pull requests do not need a twelve-minute packet, and the process would look like ceremony. Security issues that cannot discuss the exploit path in public should stay in the project's private disclosure channel. Contributors who cannot run the failing command at all should not invent passing answers for a server they never invoked. Projects that forbid model-assisted patches in &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; should skip the drafting step and fill the bank by hand, or skip the bank.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Typo-only or comment-only pull requests&lt;/li&gt;
&lt;li&gt;Private security disclosures that cannot describe the failure mode&lt;/li&gt;
&lt;li&gt;Patches the contributor cannot execute on a clean checkout&lt;/li&gt;
&lt;li&gt;Repositories that ban model-assisted contributions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The next time a crash fix looks ready, the contributor can spend twenty minutes answering the questions a tired maintainer will ask anyway. The resulting packet does not make the patch correct, but it makes incorrectness cheaper to see. A filled bank also gives a coding model a narrower job than rewriting a module until continuous integration turns green. That narrower job is the difference between a reviewable patch and a fluent diff that still stalls for days.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>git</category>
      <category>testing</category>
      <category>ai</category>
    </item>
    <item>
      <title>A One-Command Reproducer Kit That Survives a Clean OSS Checkout</title>
      <dc:creator>Blake Yang</dc:creator>
      <pubDate>Sun, 20 Sep 2026 10:57:53 +0000</pubDate>
      <link>https://dev.to/datars_7274/a-one-command-reproducer-kit-that-survives-a-clean-oss-checkout-38fc</link>
      <guid>https://dev.to/datars_7274/a-one-command-reproducer-kit-that-survives-a-clean-oss-checkout-38fc</guid>
      <description>&lt;p&gt;A contributor opened a pull request against a popular HTTP client with a three-line timeout fix and a screenshot. Maintainers could not reproduce the hang on CI, so the branch sat idle across two review cycles. The hidden cause was a leftover &lt;code&gt;HTTP_PROXY&lt;/code&gt; export in a shell profile plus a vendored snapshot that no longer matched &lt;code&gt;main&lt;/code&gt;. The patch itself was reasonable; the missing artifact was a reproduction kit that survived a clean clone.&lt;/p&gt;

&lt;p&gt;Industry chatter in mid-September 2026 keeps returning to the same failure mode: generated diffs look complete while the engineering work around them is skipped. Open-source review is where that gap becomes public. A maintainer cannot merge a story about a laptop. A maintainer can merge a command that fails the same way on a fresh tree.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dirty trees hide the actual bug
&lt;/h2&gt;

&lt;p&gt;Local developer machines accumulate exports, toolchains, cached wheels, and half-applied patches that never exist on a maintainer laptop. A failure that depends on that residue will vanish the moment someone clones the repository into an empty directory. Maintainers then spend review time debugging the reporter's environment instead of the library. A clean-clone gate makes that class of confusion expensive for the contributor and cheap for the project.&lt;/p&gt;

&lt;p&gt;Screenshots, truncated logs, and "it works on my machine after I source &lt;code&gt;.envrc&lt;/code&gt;" notes do not travel. They also do not bisect. The kit described here is the first deliverable of an OSS bugfix, not an afterthought pasted under the diff. The patch comes only after the kit fails for the same reason in two isolated trees.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the kit must contain
&lt;/h2&gt;

&lt;p&gt;A useful kit is not a paragraph of remembered steps inside the issue form. It is a script, a pinned revision, an expected failure, and a short environment dump that another person can run without extra narrative. The kit should fail for the same observable reason on two machines before any production patch is written. The following items are the minimum set for most application-level bugs in published libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pinned upstream remote plus a commit SHA or release tag&lt;/li&gt;
&lt;li&gt;one command that exits non-zero while the bug is present&lt;/li&gt;
&lt;li&gt;captured tool versions for the language, package manager, compiler, and OS&lt;/li&gt;
&lt;li&gt;explicit unset of proxy, credential, and vendor-cache variables&lt;/li&gt;
&lt;li&gt;a recorded last-known-good tag when the reporter already has that information&lt;/li&gt;
&lt;li&gt;a short expected-versus-actual block that a stranger can compare by eye&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The kit is not a substitute for the project's own test suite. It is a passport that lets a stranger reach the failing assertion without inheriting the reporter's shell.&lt;/p&gt;

&lt;h2&gt;
  
  
  A one-command template
&lt;/h2&gt;

&lt;p&gt;The script below is a labeled template, not a captured run from a specific repository. Operators should replace the remote, SHA, language toolchain, and failing invocation with values from the issue they are actually working. The important property is isolation: a temporary directory, a fresh clone, and an environment that starts empty of proxy and virtualenv hints.&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="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# repro_kit.sh — labeled template for a clean-clone OSS reproducer&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;REMOTE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;REMOTE&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;https&lt;/span&gt;://github.com/example/http-client.git&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;SHA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SHA&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;a1b2c3d4e5f60718293a4b5c6d7e8f9012345678&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;WORKDIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;mktemp&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; /tmp/oss-repro.XXXXXX&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;trap&lt;/span&gt; &lt;span class="s1"&gt;'rm -rf "$WORKDIR"'&lt;/span&gt; EXIT

&lt;span class="c"&gt;# Strip common local residue that maintainers will not have.&lt;/span&gt;
&lt;span class="nb"&gt;unset &lt;/span&gt;HTTP_PROXY HTTPS_PROXY ALL_PROXY http_proxy https_proxy all_proxy &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
unset &lt;/span&gt;VIRTUAL_ENV PYTHONPATH NODE_PATH GOPATH GOFLAGS CARGO_HOME &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/usr/bin:/bin:/usr/local/bin"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"workdir=&lt;/span&gt;&lt;span class="nv"&gt;$WORKDIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"uname=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; python3 &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; python3 &lt;span class="nt"&gt;--version&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; git &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git &lt;span class="nt"&gt;--version&lt;/span&gt;

git clone &lt;span class="nt"&gt;--quiet&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$REMOTE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$WORKDIR&lt;/span&gt;&lt;span class="s2"&gt;/src"&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$WORKDIR&lt;/span&gt;&lt;span class="s2"&gt;/src"&lt;/span&gt;
git checkout &lt;span class="nt"&gt;--quiet&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SHA&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"HEAD=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git rev-parse HEAD&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"describe=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git describe &lt;span class="nt"&gt;--always&lt;/span&gt; &lt;span class="nt"&gt;--dirty&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Project-specific install. Keep it deterministic; avoid user-site packages.&lt;/span&gt;
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv
&lt;span class="c"&gt;# shellcheck disable=SC1091&lt;/span&gt;
&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
python &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt;

&lt;span class="c"&gt;# The single failing command. Replace with the issue's minimal trigger.&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; +e
python - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;PY&lt;/span&gt;&lt;span class="sh"&gt;'
from client import Session

s = Session(timeout=0.05)
try:
    s.get("https://example.invalid/slow")
    raise SystemExit("expected timeout, got success")
except Exception as exc:
    name = type(exc).__name__
    if name != "Timeout":
        print(f"actual_exception={name}: {exc}")
        raise SystemExit(2)
    print(f"reproduced:{name}")
    raise SystemExit(1)
&lt;/span&gt;&lt;span class="no"&gt;PY
&lt;/span&gt;&lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"repro_exit=&lt;/span&gt;&lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A passing mental check for this script is simple. A stranger with network access and the language toolchain should reach the same non-zero exit without reading the pull request. If the script needs a paragraph of preamble, the kit is still a blog post and not yet a kit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Expected versus actual, in the repo
&lt;/h2&gt;

&lt;p&gt;Issue threads lose formatting and lose files. Checking a tiny sidecar into the branch keeps the contract next to the script. The file below is also a template; the strings must come from a real run, not from memory of the original crash.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# repro_kit.expect
remote: https://github.com/example/http-client.git
sha: a1b2c3d4e5f60718293a4b5c6d7e8f9012345678
command: python repro_min.py
expected_exit: 1
expected_stderr_contains: reproduced:Timeout
forbidden_stderr: HTTP_PROXY
last_known_good_tag: v2.4.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store the script and the expect file in a directory that reviewers can delete after merge, such as &lt;code&gt;repro/issue-8412/&lt;/code&gt;. Do not hide them inside a personal gist that will rot. The pull request body should link to the path and paste the last local run, including &lt;code&gt;HEAD&lt;/code&gt; and &lt;code&gt;repro_exit&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision table: when the kit is honest
&lt;/h2&gt;

&lt;p&gt;Use the table before writing production code. Each row is a gate. A "no" in the remote column means the bug is still a local myth, even if the laptop demo looks perfect.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Observation after &lt;code&gt;repro_kit.sh&lt;/code&gt;
&lt;/th&gt;
&lt;th&gt;Local dirty tree&lt;/th&gt;
&lt;th&gt;Fresh &lt;code&gt;/tmp&lt;/code&gt; clone&lt;/th&gt;
&lt;th&gt;Remote clean machine&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Same non-zero exit and same exception name&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;Write the patch; kit is load-bearing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fails locally, passes on fresh clone&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;Stop; inspect exports, caches, extra remotes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fails on fresh clone, passes on remote&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;Record OS, CPU, and filesystem; do not send a Linux-only guess&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Passes everywhere, including the reported SHA&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;The issue is closed or mis-filed; do not invent a fix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fails with different exceptions across machines&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;Narrow the trigger; the kit is still too wide&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Requires secrets, production data, or a private registry&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;maybe&lt;/td&gt;
&lt;td&gt;maybe&lt;/td&gt;
&lt;td&gt;Do not publish the kit; use a redacted fixture or a private maintainer channel&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The interesting row is the second one. That is the screenshot pull request. The clean clone is the cheapest way to discover it before a maintainer does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run the kit where the laptop cannot help
&lt;/h2&gt;

&lt;p&gt;A second machine is not a luxury for this workflow. It is the control group. Continuous integration on the fork is one control group, provided the workflow file does not reuse caches that hide the bug. A disposable remote workspace is another, provided it starts without the reporter's &lt;code&gt;direnv&lt;/code&gt;, keychain, or Docker layer cache.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach. MonkeyCode offers free model access and a free server option that can host a throwaway clone for this control-group run. The models are useful later for reviewing the kit text; the server is useful now because it does not inherit the laptop's residue. No quota, model catalog, or hardware profile is claimed here, because those details change and do not belong in a frozen article.&lt;/p&gt;

&lt;p&gt;A practical remote pass looks like the following sequence. Clone into a new directory, copy only &lt;code&gt;repro_kit.sh&lt;/code&gt; and &lt;code&gt;repro_kit.expect&lt;/code&gt;, and refuse to copy &lt;code&gt;.env&lt;/code&gt;, &lt;code&gt;venv&lt;/code&gt;, or &lt;code&gt;node_modules&lt;/code&gt;. Run the script once, capture stdout and stderr to a file, and attach that file to the issue. If the remote exit code disagrees with the laptop, the patch waits.&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="c"&gt;# Labeled example: capture a remote control-group run.&lt;/span&gt;
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x repro_kit.sh
./repro_kit.sh &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; repro_remote.log 2&amp;gt;&amp;amp;1
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"remote_exit=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; repro_remote.log
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'^(HEAD|describe|repro_exit|reproduced:|actual_exception=)'&lt;/span&gt; repro_remote.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Free-model review of the kit, not the vibes
&lt;/h2&gt;

&lt;p&gt;Generated patches often read as confident while the reproduction story remains sloppy. The safer use of a free coding model in this workflow is editorial, and it happens before the production diff exists. Paste the script, the expect file, and the draft issue comment. Ask for a maintainer-facing review of clarity, not for a speculative fix.&lt;/p&gt;

&lt;p&gt;A prompt that stays inside that boundary looks like the block below. It is labeled, because it is a proposal rather than a log from a particular model run.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are reviewing an OSS reproduction kit, not writing a patch.
Point out missing pins, leftover environment coupling, and claims
that a stranger cannot verify with one command. List concrete edits
to repro_kit.sh, repro_kit.expect, and the issue comment. Do not
propose production code. Do not invent versions I did not supply.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Treat the model output as a diff against the kit. Keep every edit that removes hidden state, vague verbs, or un-pinned installs. Discard advice that adds a rewrite of the library. If the model wants to "just catch Timeout and retry," the workflow has already failed, because the task was documentation of the bug, not product design.&lt;/p&gt;

&lt;p&gt;After the kit is tightened, a second short pass can check the pull request body for maintainer time costs. Useful flags include missing SHA, missing exit code, commands that assume a particular absolute path, and logs that still contain home-directory fragments. Those are review comments the reporter can fix without waiting for a human round trip.&lt;/p&gt;

&lt;h2&gt;
  
  
  Only then write the patch
&lt;/h2&gt;

&lt;p&gt;Once local fresh-clone and remote clean-machine runs agree, the patch has a job: make &lt;code&gt;repro_kit.sh&lt;/code&gt; exit zero for the right reason. Keep the kit on the branch until reviewers say otherwise. A green kit plus a green project test suite is a stronger story than a green suite alone, because the suite may never have covered the reported path.&lt;/p&gt;

&lt;p&gt;Commit shape still matters. One commit should add the kit and show the failure on the parent SHA if the project's CI will allow a known-failing commit. The next commit should contain the fix and the permanent regression test that will remain after &lt;code&gt;repro/&lt;/code&gt; is deleted. Do not squash away that history if the project likes bisectable series. The kit is evidence; the regression test is the long-term contract.&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="c"&gt;# Labeled local sequence after both environments agree on the failure.&lt;/span&gt;
git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; issue-8412-timeout-repro
git add repro/issue-8412/repro_kit.sh repro/issue-8412/repro_kit.expect
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"repro: add clean-clone kit for issue 8412"&lt;/span&gt;

&lt;span class="c"&gt;# ... implement the library fix and a permanent test ...&lt;/span&gt;
git add src tests
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"fix: surface Timeout when the deadline is already expired"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the permanent test cannot be written without the kit's private fixture, the fixture needs to be reduced until it can live under &lt;code&gt;tests/&lt;/code&gt;. A kit that cannot be turned into a project test is still valuable for triage, but it should not be the only safety net after merge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;This workflow assumes the bug is deterministic enough to fail a script twice. Flaky timing bugs, GPU-only faults, and races that need hours of load will not honor a one-command kit. Hardware-specific failures need a documented machine profile that a free generic server will not provide. The clean-clone gate also assumes the project can be built by a stranger from a tag; monorepos that require internal Bazel seeds or private wheels need a reduced public fixture first.&lt;/p&gt;

&lt;p&gt;The workflow is the wrong tool for embargoed security reports. A public reproducer kit that demonstrates a practical exploit does not belong on a fork. Those issues follow the project's security policy, which often means a private channel and a delayed disclosure, not a &lt;code&gt;repro/&lt;/code&gt; directory on a personal branch. License and CLA constraints are also out of scope for the script; they still block the pull request even when the kit is perfect.&lt;/p&gt;

&lt;p&gt;Free model access will not know whether the exception name is stable across minor tags. Free remote machines will not magically match an affected user's older distro. Both are controls against local dirt, not oracles. When the table's remote column cannot be filled, say so in the issue instead of implying a complete matrix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should skip this approach
&lt;/h2&gt;

&lt;p&gt;Drive-by typo fixes, documentation-only pull requests, and issues already failing on upstream CI do not need a personal reproducer kit. Maintainers who already pasted a failing job URL have done the isolation work. Contributors without permission to clone the code, or without a legal right to redistribute a fixture, should stop at a redacted description and wait for maintainer instructions.&lt;/p&gt;

&lt;p&gt;Teams that punish extra files on a branch may prefer a gist or a CI job, but the isolation rules stay the same. The method is for reporters who are about to change shared behavior and who need a stranger to believe the bug exists. Readers who want a disposable machine for the control-group step can use MonkeyCode's free server option with its free model access, then keep the kit in the pull request regardless of where it was run.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>testing</category>
      <category>git</category>
      <category>ai</category>
    </item>
    <item>
      <title>Classify the Public Surface Before an OSS Crash Fix Hits Review</title>
      <dc:creator>Blake Yang</dc:creator>
      <pubDate>Sat, 19 Sep 2026 09:15:48 +0000</pubDate>
      <link>https://dev.to/datars_7274/classify-the-public-surface-before-an-oss-crash-fix-hits-review-25ll</link>
      <guid>https://dev.to/datars_7274/classify-the-public-surface-before-an-oss-crash-fix-hits-review-25ll</guid>
      <description>&lt;p&gt;Consider a mid-size TypeScript CLI that received a three-line pull request stopping a null crash in flag parsing. The reporter attached a passing unit test, a screenshot of the local run, and a short stack note. Maintainers still closed the request after one pass because an exported helper changed return values for empty argv. Downstream packages had treated that helper as a stable contract, so the crash fix was a breaking change wearing patch-sized clothing.&lt;/p&gt;

&lt;p&gt;Correctness is not the only gate on an upstream pull request for libraries that already have downstream dependents in late 2026. Maintainers also protect exported names, documented flags, config keys, and the promise implied by the next version tag. A contributor who only proves the bug is gone still leaves contract classification sitting on the reviewer. The packet below keeps a human in charge of reproduce, patch, and test, then records a Semver Impact Card before anyone files the diff.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why small crash fixes still stall on versioning
&lt;/h2&gt;

&lt;p&gt;Issue threads reward a green test and a short, readable diff against the reported file. Versioning rewards a boring, named claim about what downstream code may keep calling after the next tag. Those two rewards pull in opposite directions when a crash lives inside a helper that already ships in &lt;code&gt;__all__&lt;/code&gt;, &lt;code&gt;export&lt;/code&gt;, or a public header. The helper can start returning a documented empty object instead of throwing, which is kinder to interactive users and still a meaning change for callers that caught the exception.&lt;/p&gt;

&lt;p&gt;Review time then migrates from the hunk to an argument about frozen intent. Maintainers compare README examples, type stubs, changelog footnotes, and the last tagged tarball. Contributors repeat that the crash was never written down as a feature. The Semver Impact Card moves that argument into a table before the pull request exists, so the first human review starts on a classified claim rather than on informal confidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four stages before &lt;code&gt;gh pr create&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The working sequence is reproduce, patch, test, and classify. Each stage writes a file under &lt;code&gt;.patch-packet/&lt;/code&gt; so the pull request can link evidence instead of retelling the narrative. Model output appears only after the first three stages are green on a clean tag, because a model that reviews a still-failing tree invents compatibility stories.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reproduce the reported failure on the issue tag, not on a dirty local &lt;code&gt;main&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Patch the owning module without drive-by refactors or formatting sweeps.&lt;/li&gt;
&lt;li&gt;Run the project's test runner plus one new assertion that binds the contract.&lt;/li&gt;
&lt;li&gt;Fill the Semver Impact Card and invite a model to falsify the proposed bump.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Stage 1: Reproduce on the reported tag
&lt;/h3&gt;

&lt;p&gt;Check out the tag named in the issue, not a local branch that already contains extra commits. A dirty tree hides whether upstream already shipped a fix, which makes any compatibility claim dishonest. Record the command, expected output, and observed output in &lt;code&gt;repro.md&lt;/code&gt; beside a tiny shell wrapper that exits non-zero on the broken tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git fetch &lt;span class="nt"&gt;--tags&lt;/span&gt; origin
git switch &lt;span class="nt"&gt;--detach&lt;/span&gt; v4.2.1
python &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;".[dev]"&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; .patch-packet

&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .patch-packet/repro.sh &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
#!/usr/bin/env bash
set -euo pipefail
# Documented contract: empty argv yields an empty object and exit 0.
# Observed on v4.2.1: TypeError from parse_argv([]).
python -m samplecli parse --argv '' --format json
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x .patch-packet/repro.sh
./.patch-packet/repro.sh&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"exit=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The wrapper must fail on the tagged release and later pass on the patched tree. If it cannot fail on that tag, the issue is not isolated enough for a compatibility claim, and the card should not be filled yet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 2: Patch the owning module only
&lt;/h3&gt;

&lt;p&gt;Keep the diff inside the file that owns the crash path. Cross-cutting cleanups belong in a follow-up issue, not in a crash fix that also claims a version bump. After the edit, store a unified diff and a name-only file list next to the card so later review does not depend on a working tree.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff &lt;span class="nt"&gt;--stat&lt;/span&gt;
git diff &lt;span class="nt"&gt;-U3&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; src/samplecli/parse.py &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .patch-packet/patch.diff
git diff &lt;span class="nt"&gt;--name-only&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .patch-packet/files.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A crash fix in this shape is usually a null guard plus a default that already appears in the docs. If the hunk set grows past the failing function, split the work before filling the card, because extra files inflate the public-surface table without extra evidence.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 3: Bind the new behavior with the project runner
&lt;/h3&gt;

&lt;p&gt;Call the same runner the CI workflow already uses. Add one assertion that encodes the old crash input and the intended contract, then keep neighboring tests unmodified unless they encoded the crash as expected behavior. Do not introduce a second framework for a single upstream patch, because reviewers will not install it.&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="c1"&gt;# tests/test_parse_empty_argv.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;samplecli.parse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;parse_argv&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_empty_argv_returns_empty_object_without_raising&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_argv&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;flags&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;positionals&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]}&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;help&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;flags&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 shell"&gt;&lt;code&gt;pytest &lt;span class="nt"&gt;-q&lt;/span&gt; tests/test_parse_empty_argv.py tests/test_parse.py
git add tests/test_parse_empty_argv.py src/samplecli/parse.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Green tests still do not prove that exported meaning stayed compatible for downstream imports. That proof is the card in the next stage, not another assertion about private helpers or log lines.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 4: Classify public surface before the pull request
&lt;/h3&gt;

&lt;p&gt;Copy the template into &lt;code&gt;.patch-packet/semver-impact.md&lt;/code&gt; and complete every field on the same day as the diff. Blank cells are a stop for the contributor, not a reminder for the maintainer to finish the taxonomy. The proposed bump must cite the project's own versioning document, even when that document is only a short README section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Artifact: the Semver Impact Card
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Semver Impact Card&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Project / issue: samplecli#1842
&lt;span class="p"&gt;-&lt;/span&gt; Base tag: v4.2.1
&lt;span class="p"&gt;-&lt;/span&gt; Proposed bump: PATCH | MINOR | MAJOR
&lt;span class="p"&gt;-&lt;/span&gt; Versioning source: VERSIONING.md (commit abc1234) or README "Versioning"

&lt;span class="gu"&gt;## Public surface touched&lt;/span&gt;
| Kind | Name | Before | After | Visible to downstream? |
| ---- | ---- | ------ | ----- | ---------------------- |
| function | parse_argv | raises TypeError on [] | returns empty object | yes, listed in __all__ |
| CLI flag | --format | unchanged | unchanged | yes |
| config key | (none) | | | |
| file format | (none) | | | |

&lt;span class="gu"&gt;## Classification rules used&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; MAJOR: remove or rename an export, change return meaning, or reject previously valid input
&lt;span class="p"&gt;-&lt;/span&gt; MINOR: add an export or optional flag whose default preserves old calls
&lt;span class="p"&gt;-&lt;/span&gt; PATCH: fix a crash or wrong result without changing documented meaning

&lt;span class="gu"&gt;## Claim&lt;/span&gt;
PATCH. &lt;span class="sb"&gt;`parse_argv([])`&lt;/span&gt; now matches the documented empty-object example in README.md.
The TypeError was never listed as a contract in VERSIONING.md or the type stubs.

&lt;span class="gu"&gt;## Explicit non-claims&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Does not add --strict
&lt;span class="p"&gt;-&lt;/span&gt; Does not change JSON key order
&lt;span class="p"&gt;-&lt;/span&gt; Does not backport to the 3.x line

&lt;span class="gu"&gt;## Tests that bind the claim&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; tests/test_parse_empty_argv.py (new)
&lt;span class="p"&gt;-&lt;/span&gt; tests/test_parse.py (unchanged, still green)

&lt;span class="gu"&gt;## Items for maintainer confirmation&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Confirm parse_argv is public because __all__ includes it
&lt;span class="p"&gt;-&lt;/span&gt; Confirm the README example, not the TypeError, is the frozen contract
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The table is the artifact a maintainer can scan without opening every hunk. The non-claims section matters as much as the bump, because it blocks extra behavior from sneaking into the pull request title. Store the filled card in git even if the project will not merge the &lt;code&gt;.patch-packet/&lt;/code&gt; directory, then paste a summary into the pull request body.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extract candidate exports from the unified diff
&lt;/h2&gt;

&lt;p&gt;Hand-filled tables miss aliases, re-exports, and definitions added only as &lt;code&gt;+export&lt;/code&gt;. A small illustrative script greps added definition lines, then checks &lt;code&gt;__all__&lt;/code&gt; on the current file. The output is a candidate list for the card, not a legal API boundary and not a substitute for reading VERSIONING.md.&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="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;semver_scan.py — list definition lines in a unified diff (illustrative).&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="n"&gt;DEF_RE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;^\+\s*(?:export\s+)?(?:async\s+)?(?:def|function|class|const|exports\.)\s*([A-Za-z_][\w.]*)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ALL_RE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__all__\s*=\s*\[([^\]]*)\]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;definitions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&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;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splitlines&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DEF_RE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&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;match&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;public_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;py_source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&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;set&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ALL_RE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;py_source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tok&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tok&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,&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;tok&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;definitions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;definitions_added_or_modified:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  - &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&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="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;public_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;in__all__:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  - &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pub&lt;/span&gt;&lt;span class="si"&gt;}&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;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&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 shell"&gt;&lt;code&gt;python .patch-packet/semver_scan.py .patch-packet/patch.diff src/samplecli/parse.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Label the script illustrative, because languages disagree about the word public. Go uses capitalization, Rust uses &lt;code&gt;pub&lt;/code&gt; and &lt;code&gt;pub use&lt;/code&gt;, C uses installed headers, and TypeScript uses &lt;code&gt;export&lt;/code&gt;. The card must accept or reject each candidate by name, including names the scanner never saw because they live only in documentation examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Falsify the bump with a free model after tests pass
&lt;/h2&gt;

&lt;p&gt;A language model is a weak author of production hunks and a useful adversary for a versioning claim. The human still reproduces the crash, writes the change, and runs the project test runner. The model receives only the card, the unified diff, and VERSIONING.md, then tries to show that the bump is too low, too high, or unsupported by the files.&lt;/p&gt;

&lt;p&gt;Contributors without a private GPU can run that second pass on a free model endpoint. MonkeyCode currently offers free model access and a free server option for this kind of review host. Disclosure: This article was prepared as part of MonkeyCode's product outreach. Teams that want a hosted loop for the review prompt can use the free server option as one of several possible hosts. The product is not required; any local endpoint that accepts a text prompt can execute the same checklist against the packet files.&lt;/p&gt;

&lt;p&gt;Save the prompt as &lt;code&gt;.patch-packet/review-prompt.md&lt;/code&gt; and paste the card plus &lt;code&gt;git diff --name-only&lt;/code&gt; under a clear delimiter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;You are reviewing a Semver Impact Card for an upstream pull request.
Do not rewrite the patch. Do not invent symbols that are absent from the diff.

Inputs:
1) semver-impact.md
2) git diff --name-only and the unified diff
3) VERSIONING.md or the README versioning section

Tasks:
&lt;span class="p"&gt;-&lt;/span&gt; List every added, removed, or retyped name that looks exported.
&lt;span class="p"&gt;-&lt;/span&gt; State whether the proposed bump is too low, too high, or consistent.
&lt;span class="p"&gt;-&lt;/span&gt; Quote the rule from VERSIONING.md that supports that judgment.
&lt;span class="p"&gt;-&lt;/span&gt; Flag any line in Explicit non-claims that the diff already implements.
&lt;span class="p"&gt;-&lt;/span&gt; Return at most 12 lines with sections: missed_exports, bump_judgment, rule_quote, overclaims.

If evidence is missing, write insufficient evidence instead of guessing.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the prompt only after the wrapper fails on the base tag and passes on HEAD. Store the output in &lt;code&gt;.patch-packet/model-review.txt&lt;/code&gt; and treat disagreements as contributor work, not as automatic edits to &lt;code&gt;parse.py&lt;/code&gt;. A model that rewrites the hunk at this stage undoes the whole point of classifying a human patch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision table for the proposed bump
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Observation on the tagged tree&lt;/th&gt;
&lt;th&gt;Typical bump&lt;/th&gt;
&lt;th&gt;Stop filling the card if&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Crash on input the docs already allow&lt;/td&gt;
&lt;td&gt;PATCH&lt;/td&gt;
&lt;td&gt;docs and tests disagree about the input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New optional flag with a preserving default&lt;/td&gt;
&lt;td&gt;MINOR&lt;/td&gt;
&lt;td&gt;the default changes old output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Return type or error class changes for valid input&lt;/td&gt;
&lt;td&gt;MAJOR&lt;/td&gt;
&lt;td&gt;the issue asked only for a crash fix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rename of an exported helper&lt;/td&gt;
&lt;td&gt;MAJOR&lt;/td&gt;
&lt;td&gt;no alias remains for one release&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internal function only, absent from docs and &lt;code&gt;__all__&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;PATCH or no release&lt;/td&gt;
&lt;td&gt;the name appears in a public example&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The table is a starting filter for contributors who do not yet know the project's customs. The project's VERSIONING.md wins when it conflicts with this chart, and the card should quote the winning sentence. When VERSIONING.md is missing, the card should say so in the versioning-source field and propose PATCH only for undocumented crash behavior that existing tests already allowed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample pull request body
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Summary&lt;/span&gt;
Crash on empty argv in parse_argv. Packet claims PATCH against v4.2.1.

&lt;span class="gu"&gt;## Evidence&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Repro: .patch-packet/repro.sh fails on v4.2.1, passes on this branch
&lt;span class="p"&gt;-&lt;/span&gt; Test: tests/test_parse_empty_argv.py
&lt;span class="p"&gt;-&lt;/span&gt; Surface: .patch-packet/semver-impact.md
&lt;span class="p"&gt;-&lt;/span&gt; Adversarial pass: .patch-packet/model-review.txt (informational only)

&lt;span class="gu"&gt;## Maintainer confirmation requested&lt;/span&gt;
Please confirm parse_argv is public and that README empty-object example is the contract.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep the model report informational. Maintainers did not ask for a generated review persona, and a contributor should not present model prose as CI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;The scanner does not understand re-exports, decorator-wrapped APIs, or documentation-only contracts. A README sample can freeze behavior that never appears in &lt;code&gt;__all__&lt;/code&gt;, and plugin entry points can expose names that live only in packaging metadata. Generated bindings need a human pass over the installed artifact, not merely over the source diff. Model review can miss domain meaning, such as a numeric default that looks compatible but breaks a wire protocol or a sort order that tests never pinned.&lt;/p&gt;

&lt;p&gt;Free model access and a free server option do not make the review authoritative. They do not replace maintainer judgment, signed tags, or the project's CI matrix. The card also fails for embargoed security fixes that must not describe public surface in a public packet. Those patches follow the project's security policy rather than this template, and they should not be sent to a third-party endpoint.&lt;/p&gt;

&lt;p&gt;Time-sensitive product quotas, model catalogs, and hardware lists change often and are omitted here on purpose. Operators should confirm current availability on the surface they actually use, rather than copying capacity claims from a blog post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should skip this packet
&lt;/h2&gt;

&lt;p&gt;Skip the card for typo-only documentation edits and for private forks with no downstream consumers. Skip it for contributors who have not reproduced the failure on a clean tag, because there is no honest base for a bump. Skip model review when the repository forbids sending source to third-party endpoints, including patches that contain secrets, customer data, or undisclosed vulnerabilities. Skip the whole packet when the maintainer template already requires a changelog with the same fields, because duplicate paperwork helps nobody and slows the merge.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the pull request should link
&lt;/h2&gt;

&lt;p&gt;A pull request that links the repro wrapper, the new test, &lt;code&gt;semver-impact.md&lt;/code&gt;, and &lt;code&gt;model-review.txt&lt;/code&gt; gives reviewers a contract claim they can accept or correct in one pass. The patch can still be wrong on performance or style, but the argument is about a named export and a named bump. Engineering work stays in reproduce, patch, and test; the model only pressure-tests the written claim after those stages are already green.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>git</category>
      <category>testing</category>
      <category>python</category>
    </item>
    <item>
      <title>Declare the Behavior Delta Before Maintainers Open an OSS Bugfix</title>
      <dc:creator>Blake Yang</dc:creator>
      <pubDate>Fri, 18 Sep 2026 07:11:15 +0000</pubDate>
      <link>https://dev.to/datars_7274/declare-the-behavior-delta-before-maintainers-open-an-oss-bugfix-1gmm</link>
      <guid>https://dev.to/datars_7274/declare-the-behavior-delta-before-maintainers-open-an-oss-bugfix-1gmm</guid>
      <description>&lt;p&gt;A contributor cloned a popular CLI, reproduced a parser crash, and typed a confident patch in one sitting. The pull request touched a helper, two tests, and a changelog line that promised a complete fix. Maintainers opened the diff and still could not tell which captured outputs were supposed to change. Screenshots arrived later, then a second patch, then a request for logs the contributor had already discarded.&lt;/p&gt;

&lt;p&gt;That stall is common when a bugfix is treated as a narrative instead of a measurable delta. Reviewers need the command, the before output, the after output, and a short allowlist of intended change. Without those four pieces, a green local run is only a private memory of one machine. The workflow below turns that memory into files a distant maintainer can replay without extra archaeology.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treat the patch as a declared behavior delta
&lt;/h2&gt;

&lt;p&gt;An OSS bugfix is not finished when the process exits zero on one laptop. The finished unit is a declared delta: old behavior, new behavior, and the exact invocation that produces both. Code review then checks whether the git hunks are necessary for that delta, rather than guessing intent from renamed helpers. This framing also limits accidental drive-by refactors that hide inside a supposedly small fix.&lt;/p&gt;

&lt;p&gt;A useful delta statement is boring, local, and specific enough to fail in public. It names the binary or test target, the fixture, and the lines that must differ after the patch. It also names the outputs that must stay byte-identical so collateral churn cannot hide. Maintainers can reject a patch that cannot produce that statement in a few quiet minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The oracle packet
&lt;/h2&gt;

&lt;p&gt;Keep the packet beside the worktree, not inside a chat log that will rot. A simple directory is enough for most CLI tools and library bugs that fail in user space.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;oracle/
  README.md
  invoke.sh
  before.txt
  after.txt
  before.exit
  after.exit
  allowlist.txt
  observed.diff
  check_allowlist.py
  check_oracle.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each file has one job, and mixing those jobs is how packets become essays. &lt;code&gt;invoke.sh&lt;/code&gt; is the only entry point a stranger should need to execute. &lt;code&gt;before.txt&lt;/code&gt; and &lt;code&gt;after.txt&lt;/code&gt; are raw captured bytes, not edited summaries of what the contributor remembers. &lt;code&gt;allowlist.txt&lt;/code&gt; lists the fragments that are allowed to differ, and &lt;code&gt;check_oracle.sh&lt;/code&gt; fails when the live diff escapes that list.&lt;/p&gt;

&lt;h3&gt;
  
  
  README.md as the human index
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Oracle packet: parse crash on empty --config&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Upstream issue: #4182
&lt;span class="p"&gt;-&lt;/span&gt; Failing commit used for the before capture: 9f3c1aa
&lt;span class="p"&gt;-&lt;/span&gt; Invocation: ./oracle/invoke.sh
&lt;span class="p"&gt;-&lt;/span&gt; Intended delta: stderr gains a one-line usage error; process status becomes 2
&lt;span class="p"&gt;-&lt;/span&gt; Forbidden delta: stdout of &lt;span class="sb"&gt;`--help`&lt;/span&gt; and the JSON fixture under tests/data/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The README is an index so a maintainer can skip archaeology, not a second design document. Link the issue, pin the commit, and state the delta in one plain sentence. Leave motivation and design opinions in the pull request body, where discussion belongs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: freeze the failing invocation
&lt;/h2&gt;

&lt;p&gt;Do not start in the editor. Write the invocation that currently fails, including working directory and environment variables that the tool actually reads. If the bug needs a fixture, generate that fixture in the same script so the packet stays closed.&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="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# oracle/invoke.sh&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail
&lt;span class="nv"&gt;ROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/.."&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ROOT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PYTHONUNBUFFERED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;span class="c"&gt;# Status is recorded below; do not abort the script on the expected failure.&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; +e
python &lt;span class="nt"&gt;-m&lt;/span&gt; tools.parser &lt;span class="nt"&gt;--config&lt;/span&gt; tests/data/empty.toml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;oracle/stdout.txt 2&amp;gt;oracle/stderr.txt
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; oracle/exit_code.txt
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Record status, stdout, and stderr as separate streams when those streams matter to the bug. Mixing them in a terminal screenshot is how reviews lose the only signal they can replay. If a test runner can target one case, prefer that invocation over a manual CLI session with hidden shell history.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: capture the before side without editing it
&lt;/h2&gt;

&lt;p&gt;Run the frozen invocation on the parent commit that still contains the bug. Save the streams before any local patch exists in that tree. Resist the urge to trim timestamps or absolute paths by hand, because silent edits make the after file incomparable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git switch &lt;span class="nt"&gt;--detach&lt;/span&gt; 9f3c1aa
./oracle/invoke.sh
&lt;span class="nb"&gt;cp &lt;/span&gt;oracle/stderr.txt oracle/before.txt
&lt;span class="nb"&gt;cp &lt;/span&gt;oracle/exit_code.txt oracle/before.exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If logs embed clocks, hostnames, or random request ids, freeze those sources in &lt;code&gt;invoke.sh&lt;/code&gt; before treating the files as oracles. A packet that cannot be replayed tomorrow is a diary entry, not evidence. Characterization of the failure belongs in the captured bytes, not in a paraphrase of a stack trace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: apply the smallest patch that should move the delta
&lt;/h2&gt;

&lt;p&gt;Copy &lt;code&gt;before.txt&lt;/code&gt; and &lt;code&gt;before.exit&lt;/code&gt; to a safe path if the working tree will rerun the same script. Then restore a writable branch and change only what the issue asked to change. Do not fold formatter noise, comment rewrites, or unrelated helper cleanups into the same commit, because those extra hunks make the allowlist dishonest even when the crash is gone.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git switch &lt;span class="nt"&gt;--create&lt;/span&gt; fix/empty-config 9f3c1aa
&lt;span class="c"&gt;# edit tools/parser.py and the focused test only&lt;/span&gt;
git diff &lt;span class="nt"&gt;--stat&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A short self-check before capture keeps the later allowlist honest:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every edited path is named in the issue or required by the failing invocation.&lt;/li&gt;
&lt;li&gt;No lockfiles, generated docs, or IDE metadata slipped into &lt;code&gt;git status&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The changelog line, if required by the project, matches the declared delta and nothing else.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 4: capture the after side with the same invocation
&lt;/h2&gt;

&lt;p&gt;Use the identical &lt;code&gt;invoke.sh&lt;/code&gt;. If the command line changes, the packet is invalid and the README must be rewritten first. Copy the new streams into &lt;code&gt;after.txt&lt;/code&gt; and &lt;code&gt;after.exit&lt;/code&gt;, then produce a unified diff the checker can read.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./oracle/invoke.sh
&lt;span class="nb"&gt;cp &lt;/span&gt;oracle/stderr.txt oracle/after.txt
&lt;span class="nb"&gt;cp &lt;/span&gt;oracle/exit_code.txt oracle/after.exit
diff &lt;span class="nt"&gt;-u&lt;/span&gt; oracle/before.txt oracle/after.txt &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; oracle/observed.diff &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read &lt;code&gt;observed.diff&lt;/code&gt; as a product artifact, not as debug scrap from a local terminal. If the diff is empty, the patch did not change the failing behavior and review is premature. If the diff is huge, the patch changed more than the issue asked for and the allowlist will not save it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: publish an allowlist, not a vibe
&lt;/h2&gt;

&lt;p&gt;The allowlist is the original technical artifact of this workflow. It states which observed changes are load-bearing for the issue. Everything else is a defect in the packet, the invocation, or the patch itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# oracle/allowlist.txt
# One fragment per line. Lines starting with # are comments.
# EXIT: lines record an intended status change.
+error: empty --config is not a valid document
-Traceback (most recent call last):
EXIT: 1 -&amp;gt; 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The checker below is a &lt;strong&gt;proposal&lt;/strong&gt; for local use, not a harvested suite from production CI. It treats uncovered unified-diff lines as a failed packet, which is stricter than a glance at &lt;code&gt;git diff&lt;/code&gt;.&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="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Fail if oracle/observed.diff contains lines not covered by allowlist.txt.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__file__&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;
&lt;span class="n"&gt;observed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;observed.diff&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;replace&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;allow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="n"&gt;exit_rule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;raw_line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;allowlist.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;splitlines&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;raw_line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;EXIT:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;exit_rule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="n"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;uncovered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;observed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splitlines&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+++&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;---&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pat&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pat&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;uncovered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;before_exit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;before.exit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;after_exit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;after.exit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&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;exit_rule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;exit_rule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# e.g. "1 -&amp;gt; 2"
&lt;/span&gt;    &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;before_exit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; -&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;after_exit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;exit allowlist expected &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s"&gt;, got &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;before_exit&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;after_exit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;exit code changed but allowlist.txt has no EXIT: rule&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&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;uncovered&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;oracle allowlist missed these diff lines:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uncovered&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;oracle allowlist covered the observed diff&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;p&gt;Wrap the checker so a maintainer runs one script after cloning the branch.&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="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# oracle/check_oracle.sh&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail
&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; before.txt
&lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; after.txt
python3 check_allowlist.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adjust the exit-code rule to the issue rather than copying the sample. Some fixes must keep the same status and only change a message, and the allowlist should say so in words the checker can enforce.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: review the packet against the git hunks
&lt;/h2&gt;

&lt;p&gt;Once the files exist, a second reader can compare three artifacts that humans often keep in separate windows. The first is &lt;code&gt;observed.diff&lt;/code&gt;. The second is &lt;code&gt;allowlist.txt&lt;/code&gt;. The third is &lt;code&gt;git diff&lt;/code&gt; for the actual source change. Contradictions among those three are the review, not whether the patch looks tidy in isolation.&lt;/p&gt;

&lt;p&gt;A narrow prompt keeps that second reader on the packet. The block below is a &lt;strong&gt;template&lt;/strong&gt;, not a transcript of a run performed for this article.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are reviewing an OSS bugfix packet, not writing new code.
Inputs: issue excerpt, git diff, oracle/before.txt, oracle/after.txt,
oracle/allowlist.txt, oracle/observed.diff, oracle/invoke.sh.
Report only:
1. Allowlist claims that do not appear in observed.diff
2. Observed.diff lines that the allowlist does not mention
3. Git hunks that cannot be tied to the declared delta
4. Steps in invoke.sh that look non-deterministic (time, net, random)
Do not suggest extra features. Do not rewrite the patch.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach. Free model access can run that constrained pass over the packet, and the free server option can replay &lt;code&gt;invoke.sh&lt;/code&gt; plus &lt;code&gt;check_oracle.sh&lt;/code&gt; on a machine that is not already loaded with the contributor's daemons. The packet remains the useful artifact if both of those options are skipped.&lt;/p&gt;

&lt;p&gt;Local caches, language shims, and half-installed extras are a frequent source of unreproducible fixes that only exist on one laptop. A clean clone that reproduces &lt;code&gt;before.txt&lt;/code&gt; and then &lt;code&gt;after.txt&lt;/code&gt; is part of the proof. If a shared server is used for that clone, scrub host paths, tokens, and customer fixtures from the oracle files before they leave the machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision table for the packet
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal in the packet&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Action before opening a PR&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;observed.diff&lt;/code&gt; is empty&lt;/td&gt;
&lt;td&gt;The patch did not move the failing behavior&lt;/td&gt;
&lt;td&gt;Keep debugging; do not request review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Diff is large, allowlist is short&lt;/td&gt;
&lt;td&gt;Hidden refactors or noisy logs&lt;/td&gt;
&lt;td&gt;Split the commit or quiet the invocation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Allowlist mentions lines absent from the diff&lt;/td&gt;
&lt;td&gt;The declaration is aspirational&lt;/td&gt;
&lt;td&gt;Rewrite the allowlist against real bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exit code unchanged when the issue needs a status change&lt;/td&gt;
&lt;td&gt;Incomplete fix&lt;/td&gt;
&lt;td&gt;Add an &lt;code&gt;EXIT:&lt;/code&gt; rule and recapture&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Invocation embeds timestamps or absolute home paths&lt;/td&gt;
&lt;td&gt;Replay will rot on another host&lt;/td&gt;
&lt;td&gt;Fix &lt;code&gt;invoke.sh&lt;/code&gt; before any model pass&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;This workflow assumes a deterministic invocation. Flaky tests, live network calls, and clocks inside log lines will poison &lt;code&gt;before.txt&lt;/code&gt; and &lt;code&gt;after.txt&lt;/code&gt; on the second run. Binary fixtures and huge snapshot dumps also make the packet hard to review, so a focused assertion beats megabytes of pretty-printed JSON.&lt;/p&gt;

&lt;p&gt;The allowlist checker is string oriented on purpose. It can miss semantic changes that keep the same text, and it can flag harmless path reordering that still confuses a reviewer. Contributors still need a human pass on the git hunks, especially around public API and error-code stability. A model will not see uncommitted files, private credentials in environment dumps, or project policy on breaking changes.&lt;/p&gt;

&lt;p&gt;Do not paste secrets into a shared server or a model prompt. Oracle files often contain host paths, tokens from failed auth, or fixtures that should never be public. If the bug only reproduces with proprietary data, a public before-and-after packet is the wrong shape for the proof.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should skip this approach
&lt;/h2&gt;

&lt;p&gt;Maintainers of one-line typo fixes do not need an oracle directory sitting in the review. Security patches that should not advertise exploit details in before and after logs should use a private disclosure channel instead of this packet. Contributors without a failing invocation, including design debates and API proposals, should write a decision record rather than invent a fake output pair.&lt;/p&gt;

&lt;p&gt;Teams that already have a golden-test harness covering the same invocation can point the pull request at that harness and skip the extra files. The principle remains even then: declare the delta, prove it on both sides of the patch, and keep the proof next to the diff. Chat summaries disappear; replayable bytes do not.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>testing</category>
      <category>git</category>
      <category>ai</category>
    </item>
    <item>
      <title>Pin the Crash in a Characterization Test Before You Patch Upstream</title>
      <dc:creator>Blake Yang</dc:creator>
      <pubDate>Thu, 17 Sep 2026 05:19:50 +0000</pubDate>
      <link>https://dev.to/datars_7274/pin-the-crash-in-a-characterization-test-before-you-patch-upstream-knf</link>
      <guid>https://dev.to/datars_7274/pin-the-crash-in-a-characterization-test-before-you-patch-upstream-knf</guid>
      <description>&lt;p&gt;A first-time contributor cloned a popular command-line tool and reproduced a parsing crash within minutes of setup. The stack trace pointed at a single helper, so the contributor inserted a defensive return and watched the process exit cleanly. The pull request still stalled because maintainers could not replay the old failure against the new tree. They needed a test that encoded the crash, not a narrative that the path now succeeded.&lt;/p&gt;

&lt;p&gt;This article describes a characterization-first workflow for open-source bug patches inside libraries and command-line tools. The method records buggy behavior as an executable oracle before any production source file is changed. Free coding models may review that oracle for weak assertions after the crash is pinned locally. The procedure below is proposed sample material rather than a measured result from any one repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Happy-path diffs still bounce in review
&lt;/h2&gt;

&lt;p&gt;Open-source maintainers read stranger diffs under time pressure and with incomplete local context around the crash. A patch that only proves a new success path leaves the original failure as folklore inside the issue thread. Characterization tests freeze observed behavior so later production edits cannot drift without a failing automated suite.&lt;/p&gt;

&lt;p&gt;Michael Feathers described characterization tests for untested code that teams must change under real maintenance risk. The same idea helps first-time contributors who lack a mental model of every upstream caller. An oracle that fails on unpatched &lt;code&gt;main&lt;/code&gt; and passes after the fix gives reviewers a replay button.&lt;/p&gt;

&lt;p&gt;Common holes appear in first patches for crashing CLIs and libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The reproduction lives in a screenshot or comment instead of &lt;code&gt;tests/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The new test asserts the desired API, so it cannot fail on &lt;code&gt;main&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The fix changes return values that other callers still depend on.&lt;/li&gt;
&lt;li&gt;Continuous integration stays green because the suite never sent the crashing input.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A useful oracle fails on the unpatched tree and passes on the patched commit for one named input. Maintainers can then replay the crash without reconstructing the original issue from screenshots and comment threads. Contributors should refuse to open the pull request until that replay exists in the test tree. Folklore in the issue tracker is not an acceptable substitute for that recorded executable failure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Capture the crash before production edits
&lt;/h2&gt;

&lt;p&gt;The contributor should stop after reproduction and write a test that documents current behavior, including the crash. That test may expect an exception, a nonzero process exit, or a known-bad stdout fixture on disk. Production files stay untouched until the oracle lives on a local branch that still matches upstream &lt;code&gt;main&lt;/code&gt;. Only then does a later source change have a failing baseline that reviewers can move with confidence.&lt;/p&gt;

&lt;p&gt;The following Python example is a proposed template for a CLI parser that dies on an empty flag value. It is unexecuted sample code and not a harvested result from any named upstream project. Reviewers should adapt file paths and exception names to the real tree before running any command. Inline comments mark the file as characterization work rather than as a finished contract test.&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="c1"&gt;# tests/test_characterize_empty_flag.py
# Proposed characterization oracle. Unexecuted example.
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="n"&gt;CLI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__file__&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;parents&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;src&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cli.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_cli&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CLI&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;capture_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_empty_flag_currently_crashes&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Pin the bug: empty --out should not be a silent success on main.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;run_cli&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--out&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sample.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="c1"&gt;# Characterization: record what main actually does today.
&lt;/span&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;returncode&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Traceback&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ValueError&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the unpatched tree this characterization test should pass because it still asserts the original crash. After the production fix, the same file must be rewritten to assert a controlled error message and a stable exit code. Both assertion blocks belong in the pull request notes so reviewers can inspect the behavioral flip. A short shell helper then makes that flip visible without rereading the entire test suite.&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="c"&gt;# proposed_oracle_flip.sh&lt;/span&gt;
&lt;span class="c"&gt;# Unexecuted sample: prove the oracle on main, then after the assertion rewrite.&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

git switch &lt;span class="nt"&gt;--detach&lt;/span&gt; main
python &lt;span class="nt"&gt;-m&lt;/span&gt; pytest tests/test_characterize_empty_flag.py &lt;span class="nt"&gt;-q&lt;/span&gt;
&lt;span class="c"&gt;# Expect PASS on main because the crash still exists.&lt;/span&gt;

git switch &lt;span class="nt"&gt;--detach&lt;/span&gt; HEAD@&lt;span class="o"&gt;{&lt;/span&gt;1&lt;span class="o"&gt;}&lt;/span&gt;  &lt;span class="c"&gt;# patched tree; adjust the ref as needed&lt;/span&gt;
python &lt;span class="nt"&gt;-m&lt;/span&gt; pytest tests/test_characterize_empty_flag.py &lt;span class="nt"&gt;-q&lt;/span&gt;
&lt;span class="c"&gt;# After rewriting assertions, expect PASS for the intended contract.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Label the two assertion blocks in the pull request body as &lt;code&gt;oracle-before&lt;/code&gt; and &lt;code&gt;oracle-after&lt;/code&gt; for later readers. Maintainers can replay the failure story without guessing which exception used to appear on standard error. Contributors should attach the helper output as a gist or a PR comment rather than a screenshot. Those labels keep the discussion tied to files instead of vague adjectives like fixed and broken.&lt;/p&gt;

&lt;h2&gt;
  
  
  A three-ref behavior grid
&lt;/h2&gt;

&lt;p&gt;A single passing test on the feature branch remains a weak signal for busy upstream maintainers. The same crashing input should run against the last release tag, current &lt;code&gt;main&lt;/code&gt;, and the patched commit. The grid shows whether the crash is a regression, a long-standing hole, or an environmental false alarm. Contributors should read that comparison table before they touch production parsers or shared helpers.&lt;/p&gt;

&lt;p&gt;The sample script assumes a clean throwaway clone because detached HEAD checkouts will disrupt a dirty working tree. Copy the repository into a scratch directory before looping across refs. Record fingerprints of stderr instead of full traces that include local paths. The script below is unexecuted sample material and will need real tag names.&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="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# proposed_behavior_grid.sh — unexecuted sample&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail
&lt;span class="nv"&gt;INPUT_ARGS&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="nt"&gt;--out&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; sample.txt&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;REFS&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"v1.4.0"&lt;/span&gt; &lt;span class="s2"&gt;"main"&lt;/span&gt; &lt;span class="s2"&gt;"HEAD"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"ref,exit,stderr_fingerprint"&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;ref &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;REFS&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; git switch &lt;span class="nt"&gt;--detach&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ref&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s,unbuildable,\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ref&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;continue
  fi
  &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; +e
  python src/cli.py &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INPUT_ARGS&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;out.txt 2&amp;gt;err.txt
  &lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
  &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;
  &lt;span class="nv"&gt;fp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 3 err.txt | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="s1"&gt;'\n'&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-c1-80&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s,%s,%s\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ref&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$fp&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read the grid before writing the production patch and keep the CSV in the request body. If the last release already crashes, the hole is old and the test belongs in the suite even without a fix. If only &lt;code&gt;main&lt;/code&gt; crashes, a bisect remains a separate investigation and should not mix into this oracle work. Unbuildable refs should be recorded as unbuildable in the CSV rather than as invented exit codes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let a free model review the oracle, not the patch
&lt;/h2&gt;

&lt;p&gt;Human reviewers still miss vacuous assertions, copied fixtures, and tests that never call the changed function. A coding model can critique the oracle file before the contributor edits any product source code. The prompt should ask for weak assertions, missing inputs, and accidental coupling to log wording. It should refuse any request to invent a production patch from the issue title alone.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;MonkeyCode offers free model access and a free server option for this kind of oracle review. Contributors can paste the oracle test, the public issue excerpt, and the three-ref CSV into that workspace. The model should list holes in the characterization rather than generate a speculative production fix. No model name, quota, or hardware claim is made here beyond that operator-supplied free access option. Contributors who already pin crashes locally can use that free server option when they want a second reader on the oracle file.&lt;/p&gt;

&lt;p&gt;A proposed review prompt, labeled as unexecuted sample text, follows in the fenced block below. The instructions ban product-code edits and ask only for defects inside the characterization oracle. Contributors should treat every bullet from the model as a hypothesis to prove against main. A mutated assertion that still passes on main means the check never encoded the crash.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are reviewing a characterization test, not writing a patch.
Issue excerpt:
&amp;lt;paste the frozen acceptance lines&amp;gt;

Oracle file:
&amp;lt;paste tests/test_characterize_empty_flag.py&amp;gt;

Behavior grid CSV:
&amp;lt;paste ref,exit,stderr_fingerprint&amp;gt;

List:
1. Assertions that would pass even if the crash disappeared.
2. Inputs from the issue that the oracle never sends.
3. Log phrases that will drift across versions.
4. A minimal assertion rewrite for the post-fix contract.
Do not suggest product-code edits.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Treat the chat transcript as commentary rather than as evidence attached to the pull request. If the model flags a weak assertion, mutate that assertion on &lt;code&gt;main&lt;/code&gt; and watch whether the suite still passes. That mutation check is the load-bearing step in this characterization workflow for reviewers. Maintainers should ignore a model "LGTM" that is not backed by the grid and the oracle flip.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision table for the oracle loop
&lt;/h2&gt;

&lt;p&gt;The following table is a proposed decision aid, not a measured policy from a maintainer team. It keeps free-model review inside a narrow job that starts after the crash is pinned locally. Models help find vacuous asserts and missing inputs copied poorly from the public issue. They are a poor source of the original crash record because they were not present when the process died.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal on main&lt;/th&gt;
&lt;th&gt;Oracle shape&lt;/th&gt;
&lt;th&gt;Allowed next step&lt;/th&gt;
&lt;th&gt;Stop if&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Crash with nonzero exit&lt;/td&gt;
&lt;td&gt;Expect exception or exit != 0&lt;/td&gt;
&lt;td&gt;Write a production guard&lt;/td&gt;
&lt;td&gt;Test still passes after crash is removed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wrong output with exit 0&lt;/td&gt;
&lt;td&gt;Golden stdout file&lt;/td&gt;
&lt;td&gt;Change the formatter only&lt;/td&gt;
&lt;td&gt;Golden file includes timestamps or paths&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flake only under load&lt;/td&gt;
&lt;td&gt;Do not characterize yet&lt;/td&gt;
&lt;td&gt;Capture a deterministic repro first&lt;/td&gt;
&lt;td&gt;Model invents a sleep-based test&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Missing feature, not a crash&lt;/td&gt;
&lt;td&gt;Skip characterization&lt;/td&gt;
&lt;td&gt;Write a spec test that fails on main&lt;/td&gt;
&lt;td&gt;Oracle encodes the desired API too early&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;Characterization tests freeze whatever the machine did today, including accidental environment details that will not travel. A traceback assertion that mentions a local virtualenv path will fail on CI and teach nothing about the parser. Golden files that capture full help text will churn on unrelated copy edits across later releases. Contributors should fingerprint a stable error substring rather than the entire stderr buffer from the process.&lt;/p&gt;

&lt;p&gt;The three-ref grid assumes tags are buildable with the same toolchain as &lt;code&gt;HEAD&lt;/code&gt; on the contributor laptop. Old releases may need different language versions, native extensions, or lockfiles that this sample script ignores. When a ref cannot run, the CSV should say &lt;code&gt;unbuildable&lt;/code&gt; instead of fabricating a numeric exit. That honest CSV cell still helps maintainers decide whether the crash is actually new.&lt;/p&gt;

&lt;p&gt;Model review cannot certify correctness of a patch or the absence of a regression in callers. A free server is the wrong place for secrets, unreleased customer data, or embargoed security issues. Prompts should contain only public issue text plus the contributor's own characterization oracle file. This workflow also adds latency that tiny documentation and typo fixes do not deserve.&lt;/p&gt;

&lt;p&gt;Maintainers who already requested a specific unit test in the issue should follow that written request. This template is a fallback for sparse suites, not a replacement for a named test in the ticket. Extra ceremony on a one-character patch wastes reviewer attention and delays an otherwise obvious merge. Skip the three-ref grid when the issue already pins a file, a function, and a crashing input.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should not use this approach
&lt;/h2&gt;

&lt;p&gt;Security patches that disclose an exploit path should not be developed as public characterization tests on a shared server. Contributors without a failing local repro should not ask a model to imagine the crash from the issue title. Teams that lack permission to push extra test files should not treat this article as license to expand scope. Those constraints matter more than any convenience that comes from free model access during review.&lt;/p&gt;

&lt;p&gt;The method is aimed at functional bugs in libraries and CLIs where subprocess or unit tests can pin a crash. It is a poor fit for graphical timing issues, distributed race conditions, and hardware-dependent failures in drivers. Those classes need specialized harnesses that this sample workflow does not attempt to provide. Using an oracle template in those domains creates false confidence and noisy continuous integration.&lt;/p&gt;

&lt;p&gt;Contributors who already maintain a strong, input-driven suite can skip the characterization rename step entirely. They can add a normal failing test on main and then implement the production change against that test. The oracle pattern exists for sparse suites that cannot yet name the bug in existing tests. Extra renaming on a mature suite is ceremony without new information for the reviewing maintainers.&lt;/p&gt;

&lt;p&gt;A maintainer can replay a crash that lives in &lt;code&gt;tests/&lt;/code&gt; without trusting a chat log or a screenshot from the contributor. The original contributor still owes a production fix that flips the oracle for a documented reason. Optional model commentary on that oracle is useful only after the failure is executable in tests. Recorded failures outlast the issue thread that described them only in prose and screenshots.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>testing</category>
      <category>git</category>
      <category>ai</category>
    </item>
    <item>
      <title>Trace Callers Before the Diff: A Blast-Radius Card for Shared OSS Helpers</title>
      <dc:creator>Blake Yang</dc:creator>
      <pubDate>Wed, 16 Sep 2026 03:38:43 +0000</pubDate>
      <link>https://dev.to/datars_7274/trace-callers-before-the-diff-a-blast-radius-card-for-shared-oss-helpers-1fe9</link>
      <guid>https://dev.to/datars_7274/trace-callers-before-the-diff-a-blast-radius-card-for-shared-oss-helpers-1fe9</guid>
      <description>&lt;p&gt;The following labeled scenario opens this walkthrough and does not name a public repository or vendor team. A contributor proposed a timeout fix against a shared helper that twelve command modules imported through thin wrappers. The unit file beside that helper stayed green, so the change looked complete during a fast skim. A later release candidate failed because a worker still called the previous signature through another package.&lt;/p&gt;

&lt;p&gt;Maintainers then rebuilt the call graph by hand, which delayed the tag and exhausted scarce review time. The missing artifact was not extra commentary pasted into the pull request description or chat thread. Reviewers needed a caller inventory that anyone could replay from the branch without extra tribal knowledge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a green neighbor test is not blast-radius proof
&lt;/h2&gt;

&lt;p&gt;File-local tests answer a narrow question about the hunk under the cursor and its closest fixtures. Shared helpers in open source libraries usually sit behind several import paths, generated shims, and optional extras. A green test in the same directory does not prove those paths still compile, still type-check, or still honor timeouts.&lt;/p&gt;

&lt;p&gt;Vibe-shaped patches make this gap worse because the author narrates intent instead of listing dependents. Engineering a contribution means publishing the blast radius before the diff, then refusing hunks that fall outside that card. The rest of this article is a replayable workflow for that card, including harvest commands, a contract table, and a frozen review prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  The blast-radius card maintainers can replay
&lt;/h2&gt;

&lt;p&gt;Keep one markdown file in the branch, named &lt;code&gt;BLAST_RADIUS.md&lt;/code&gt;, and treat it as a merge gate rather than decoration. The card must be complete enough that a reviewer who never joined the issue thread can still reconstruct the risk. Label the following template as a proposal that should be filled from the working tree, not from memory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Blast-radius card&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Issue: #
&lt;span class="p"&gt;-&lt;/span&gt; Symbol(s) under change:
&lt;span class="p"&gt;-&lt;/span&gt; Public signature before:
&lt;span class="p"&gt;-&lt;/span&gt; Public signature after:
&lt;span class="p"&gt;-&lt;/span&gt; Intended behavior change (one sentence):
&lt;span class="p"&gt;-&lt;/span&gt; Forbidden behavior change:
&lt;span class="p"&gt;-&lt;/span&gt; Call sites harvested (path:line):
&lt;span class="p"&gt;-&lt;/span&gt; Call sites excluded, with reason:
&lt;span class="p"&gt;-&lt;/span&gt; Tests that must change:
&lt;span class="p"&gt;-&lt;/span&gt; Tests that must stay green without edits:
&lt;span class="p"&gt;-&lt;/span&gt; New dependency allowed: yes/no
&lt;span class="p"&gt;-&lt;/span&gt; Rollback note:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three rules keep the card honest during review. Every listed call site must come from a command that a stranger can rerun. Every excluded path must carry a reason that cites an import boundary, a generated file, or an unused extra. Every intended behavior change must fit one sentence, because a second sentence usually hides a second patch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Harvest call sites from the tree, not from chat
&lt;/h2&gt;

&lt;p&gt;Start from a clean branch that tracks the issue and avoids mixed chores. Record the symbol names before editing, including aliases and re-exports that wrappers may use. The commands below are labeled examples for a Python-like tree; adapt the patterns to the language under review.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git status &lt;span class="nt"&gt;--short&lt;/span&gt;
git rev-parse &lt;span class="nt"&gt;--abbrev-ref&lt;/span&gt; HEAD

&lt;span class="c"&gt;# Example harvest for a helper named apply_timeout&lt;/span&gt;
rg &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;--hidden&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="s1"&gt;'!vendor/**'&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="s1"&gt;'!dist/**'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'apply_timeout|from \.timing import apply_timeout|timing\.apply_timeout'&lt;/span&gt;

&lt;span class="c"&gt;# Confirm the definition sites before classifying callers&lt;/span&gt;
rg &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s1"&gt;'^def apply_timeout|^async def apply_timeout'&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste every hit into the card with path and line, then classify each hit as a direct caller, a re-export, a test double, or noise. Delete noise only when the file cannot import the symbol at runtime, and write that reason beside the exclusion. A second pass with &lt;code&gt;git grep&lt;/code&gt; catches generated files that some ignore rules hide from &lt;code&gt;rg&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s1"&gt;'apply_timeout'&lt;/span&gt;
git log &lt;span class="nt"&gt;-S&lt;/span&gt; &lt;span class="s1"&gt;'apply_timeout'&lt;/span&gt; &lt;span class="nt"&gt;--oneline&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; max-count&lt;span class="o"&gt;=&lt;/span&gt;20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The history search is not a substitute for the inventory. It only shows whether the symbol recently moved, which often explains stale wrappers that tests never import. When the log shows a rename, add the old name to the harvest patterns and extend the card before any production hunk is written.&lt;/p&gt;

&lt;h3&gt;
  
  
  A small classifier script for the harvest
&lt;/h3&gt;

&lt;p&gt;The following Python sketch is an unexecuted example that turns ripgrep-style lines into a table. Run it only after redirecting harvest output to a text file, and treat its labels as hints rather than proof.&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="c1"&gt;# unlabeled proposal: classify harvested lines into a blast-radius table
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="n"&gt;KINDS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/tests/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;_test.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test_&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reexport&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__init__.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,)),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wrapper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;compat.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shims/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;classify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&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;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;needles&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;KINDS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;needles&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;caller&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;harvest.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;splitlines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;classify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="si"&gt;}&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;p&gt;Commit the harvest file beside &lt;code&gt;BLAST_RADIUS.md&lt;/code&gt; so reviewers can rerun classification without trusting a screenshot. If the classifier and the card disagree, stop and repair the card before writing product code. Disagreement at this stage is cheaper than a revert after a release candidate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Freeze a contract table before the first production hunk
&lt;/h2&gt;

&lt;p&gt;Turn the intended change into a table that later tests can fail against. Columns stay boring on purpose: input, old observable, new observable, and owners of that path. Rows that cannot name an owner do not belong in the patch.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Call site&lt;/th&gt;
&lt;th&gt;Input that matters&lt;/th&gt;
&lt;th&gt;Old observable&lt;/th&gt;
&lt;th&gt;New observable&lt;/th&gt;
&lt;th&gt;Owner test&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cmd/sync.py:88&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;HTTP client timeout&lt;/td&gt;
&lt;td&gt;30s default&lt;/td&gt;
&lt;td&gt;5s default&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tests/cmd/test_sync.py&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;worker/retry.py:41&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;retry wrapper timeout&lt;/td&gt;
&lt;td&gt;inherits helper&lt;/td&gt;
&lt;td&gt;must stay 30s&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tests/worker/test_retry.py&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;compat/old_api.py:12&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;re-export&lt;/td&gt;
&lt;td&gt;same signature&lt;/td&gt;
&lt;td&gt;same signature&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tests/compat/test_export.py&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The middle row is the reason this workflow exists. Shared helpers often have one caller that must change and another caller that must not change, and file-local tests cannot see the second caller. If the table needs more than five rows, split the work into two issues rather than smuggling a migration through a timeout fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Patch against the card, then move the tests that own the rows
&lt;/h2&gt;

&lt;p&gt;Edit production code only after the card and table are committed. Keep the diff inside the listed symbols, and reject drive-by formatting in files that are not call sites. When a wrapper needs a new argument, add it as an explicit keyword with a default that preserves the forbidden behavior change.&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="c1"&gt;# labeled example: preserve the worker path while tightening the CLI path
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;apply_timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inherit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&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;inherit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;seconds&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the owner tests named in the table before the full suite, because those tests are the contract. A patch that leaves every owner test untouched has not demonstrated the new observable. A patch that rewrites unrelated assertions has expanded the blast radius after the card was frozen, which should fail review.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pytest &lt;span class="nt"&gt;-q&lt;/span&gt; tests/cmd/test_sync.py tests/worker/test_retry.py tests/compat/test_export.py
pytest &lt;span class="nt"&gt;-q&lt;/span&gt;
git diff &lt;span class="nt"&gt;--stat&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--stat&lt;/code&gt; is part of the gate. If the file list contains modules absent from the card, restore those files or amend the card with a new harvest. Reviewers should not have to discover extra files by scrolling a surprise diff.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frozen-prompt review after the card is complete
&lt;/h2&gt;

&lt;p&gt;After the blast-radius card, the contract table, and the tests exist, a second pass can interrogate those files without extra narrative. Disclosure: This article was prepared as part of MonkeyCode's product outreach. Contributors without a spare checkout can keep that frozen packet on MonkeyCode's free server option and run the same prompt through free model access, so the model sees only the card, the harvest, and the diff.&lt;/p&gt;

&lt;p&gt;The prompt below is a labeled template. Paste the files; do not paste issue chatter, because chatter reintroduces assumptions the card was meant to kill.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are reviewing an OSS patch packet, not writing new code.
Read BLAST_RADIUS.md, harvest.txt, the contract table, and the diff.
Report only:
1) call sites in the diff that the card does not list
2) call sites on the card that the diff does not touch, with risk
3) owner tests that did not move for a changed observable
4) signature changes that violate the forbidden behavior line
Refuse to suggest extra features. If the packet is incomplete, say incomplete.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Treat the model output as a checklist against the working tree, not as a merge vote. Every finding must be confirmed with &lt;code&gt;rg&lt;/code&gt; or a failing test before the author changes code. Findings that cannot be replayed from the packet are discarded, because they are vibes wearing a reviewer's coat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision table for this workflow
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Merge stance&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Harvest and card disagree&lt;/td&gt;
&lt;td&gt;Stop and repair the card&lt;/td&gt;
&lt;td&gt;Block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Owner test did not move&lt;/td&gt;
&lt;td&gt;Add or fail the observable&lt;/td&gt;
&lt;td&gt;Block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Diff file absent from the card&lt;/td&gt;
&lt;td&gt;Restore or re-harvest&lt;/td&gt;
&lt;td&gt;Block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model flags a missing caller, &lt;code&gt;rg&lt;/code&gt; confirms&lt;/td&gt;
&lt;td&gt;Extend tests, then patch&lt;/td&gt;
&lt;td&gt;Block until green&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model flags a missing caller, &lt;code&gt;rg&lt;/code&gt; is clean&lt;/td&gt;
&lt;td&gt;Discard the finding&lt;/td&gt;
&lt;td&gt;Continue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typo in a comment only&lt;/td&gt;
&lt;td&gt;Skip the card&lt;/td&gt;
&lt;td&gt;Allow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security embargo or private fixture&lt;/td&gt;
&lt;td&gt;Do not upload the packet&lt;/td&gt;
&lt;td&gt;Use a private review path&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The table is the engineering part of the loop. Tools can harvest and nag, but they cannot decide which callers are load-bearing. Humans still own that classification, and the card makes the classification visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations and who should skip this card
&lt;/h2&gt;

&lt;p&gt;This workflow assumes the repository has searchable call sites and tests that can name an observable. Generated parsers, huge monorepos without import conventions, and binary plugins will produce noisy harvests that look complete while missing real callers. In those trees, the card still helps, but it cannot be the only gate.&lt;/p&gt;

&lt;p&gt;Authors should skip the full card for single-line comment fixes, changelog-only pull requests, and lockfile refreshes that do not touch runtime symbols. They should also skip uploading a packet that contains secrets, private customer fixtures, or embargoed vulnerability detail to any hosted model or shared server. Maintainers should reject the method when a contributor uses the model output as a substitute for running the owner tests.&lt;/p&gt;

&lt;p&gt;The approach also fails when the intended change cannot fit one sentence on the card. That failure is useful, because it usually means the issue is a migration and needs a staged plan. Splitting the work is slower on the first day and cheaper than a revert after a green-looking helper change lands.&lt;/p&gt;

&lt;p&gt;A blast-radius card does not make a patch small, and it does not make a model authoritative. It makes the dependents visible before the diff, which is the part most vibe-shaped OSS reviews still skip. Contributors who already freeze that card can run the frozen review pass with free model access when another local checkout is the wrong place for the packet.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>git</category>
      <category>testing</category>
      <category>ai</category>
    </item>
    <item>
      <title>The Hunk Necessity Test: Prove Every Line of an OSS Patch Is Load-Bearing</title>
      <dc:creator>Blake Yang</dc:creator>
      <pubDate>Mon, 14 Sep 2026 21:29:59 +0000</pubDate>
      <link>https://dev.to/datars_7274/the-hunk-necessity-test-prove-every-line-of-an-oss-patch-is-load-bearing-2e7g</link>
      <guid>https://dev.to/datars_7274/the-hunk-necessity-test-prove-every-line-of-an-oss-patch-is-load-bearing-2e7g</guid>
      <description>&lt;p&gt;A contributor fixes a three-line null check in a parser, then ships the same commit with a reformatted switch statement and two renamed locals. Six days later the pull request is still open, and the maintainer asks the question that stalls most external patches: which parts of this diff are actually required? CI is green, but a green branch only proves the suite still passes with the patch applied. It says nothing about whether every changed line earns its place in the review.&lt;/p&gt;

&lt;p&gt;This article describes a small harness that answers that question hunk by hunk. For each hunk in a patch, it reverse-applies only that hunk and reruns the pinned failing test, then records whether the test breaks again. The output is a three-value verdict per hunk, produced by the test runner rather than by opinion, and it turns a subjective "this diff feels large" comment into a table a maintainer can act on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why per-hunk evidence beats a narrated patch
&lt;/h2&gt;

&lt;p&gt;Maintainers triage far more patches than they can read closely, so they optimize for review cost. A diff that mixes a fix with unrelated cleanup forces them to do three jobs at once: find the actual fix, verify it, and audit everything else for hidden behavior change.&lt;/p&gt;

&lt;p&gt;Three failure modes show up again and again in review threads.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dead weight.&lt;/strong&gt; A hunk that no test depends on, usually a drive-by refactor, gets reverted during review or blocks the merge entirely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;False confidence.&lt;/strong&gt; A patch passes because the suite is weak, not because the change is correct, and nobody can tell which lines carried the fix.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Split requests.&lt;/strong&gt; A maintainer asks for the cleanup to move to a separate pull request, which costs the contributor another full review cycle.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A hunk necessity run front-loads that work. The contributor discovers the dead hunks before a human has to point them out, and the final patch arrives with machine-checkable evidence attached.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gate zero: the pinned test must fail before the patch
&lt;/h2&gt;

&lt;p&gt;The harness assumes a single test command that reproduces the reported bug and exits non-zero on the unfixed revision. Without that gate, the whole run is noise: if the test already passes on &lt;code&gt;HEAD&lt;/code&gt;, then every hunk will look "dead" and the table will be meaningless.&lt;/p&gt;

&lt;p&gt;Two preconditions therefore run before any hunk is touched. The patch must make the test pass, and reverting the patch must make it fail again. A contributor who cannot satisfy both conditions has a test-quality problem to solve first, not a patch-splitting problem.&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="c"&gt;# gate 0, abbreviated&lt;/span&gt;
 git apply &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PATCH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;      &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TEST_CMD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;   &lt;span class="c"&gt;# must succeed&lt;/span&gt;
 git apply &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PATCH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;   &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TEST_CMD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;   &lt;span class="c"&gt;# must fail&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The harness: split, reverse-apply, rerun
&lt;/h2&gt;

&lt;p&gt;The script below runs inside a detached worktree so the reset loop cannot touch uncommitted work in the main checkout. It splits a unified diff into one file per hunk, keeps the file headers attached to each piece, then evaluates every hunk independently.&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="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# hunk-necessity.sh &amp;lt;patch-file&amp;gt; "&amp;lt;test-command&amp;gt;"&lt;/span&gt;
&lt;span class="c"&gt;# Requires: git &amp;gt;= 2.30, a clean worktree, a test command that exits non-zero on the pinned bug.&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;PATCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;realpath&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;:?patch&lt;span class="p"&gt; file required&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;TEST_CMD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;2&lt;/span&gt;:?test&lt;span class="p"&gt; command required&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nv"&gt;ROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git rev-parse &lt;span class="nt"&gt;--show-toplevel&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;TMP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;mktemp&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;HUNKS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TMP&lt;/span&gt;&lt;span class="s2"&gt;/hunks"&lt;/span&gt;
&lt;span class="nv"&gt;RESULTS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TMP&lt;/span&gt;&lt;span class="s2"&gt;/results.tsv"&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HUNKS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;trap&lt;/span&gt; &lt;span class="s1"&gt;'git -C "$ROOT" worktree remove --force "$TMP/wt" 2&amp;gt;/dev/null || true; rm -rf "$TMP"'&lt;/span&gt; EXIT

git &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ROOT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; worktree add &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;--detach&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TMP&lt;/span&gt;&lt;span class="s2"&gt;/wt"&lt;/span&gt; HEAD
&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TMP&lt;/span&gt;&lt;span class="s2"&gt;/wt"&lt;/span&gt;

&lt;span class="c"&gt;# --- gate 0 ---&lt;/span&gt;
git apply &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PATCH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TEST_CMD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"gate0: patch does not fix the pinned test"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;2&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
git apply &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PATCH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TEST_CMD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"gate0: pinned test already passes on HEAD; it does not pin the bug"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;3
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# --- split the diff into one patch per hunk, headers included ---&lt;/span&gt;
&lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HUNKS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s1"&gt;'
  /^diff --git / { if (hunk != "") close(hunk); hunk = ""; header = $0 "\n"; next }
  /^(index |--- |\+\+\+ |new file|deleted file|similarity|rename|old mode|new mode)/ {
                    header = header $0 "\n"; next }
  /^@@/           { if (hunk != "") close(hunk);
                    hunk = sprintf("%s/hunk-%03d.patch", out, ++n);
                    printf "%s", header &amp;gt; hunk }
  hunk != ""      { print &amp;gt;&amp;gt; hunk }
'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PATCH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'hunk\tverdict\n'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RESULTS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;piece &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HUNKS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;/hunk-&lt;span class="k"&gt;*&lt;/span&gt;.patch&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;git checkout &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
  git apply &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PATCH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$piece&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; .patch&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; git apply &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$piece&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt;/dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\tentangled\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$id&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;$RESULTS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;elif &lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TEST_CMD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\tdead\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$id&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;$RESULTS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\tload-bearing\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$id&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;$RESULTS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;fi
done

&lt;/span&gt;column &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RESULTS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The harness is a starting point rather than a released tool, so treat the reset logic as reviewable code and run it on a scratch clone first. Every verdict comes from an exit code, which keeps the classification reproducible on any machine that can run the suite.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reading the verdict table
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Verdict&lt;/th&gt;
&lt;th&gt;How it is produced&lt;/th&gt;
&lt;th&gt;What to do next&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;load-bearing&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Reverse-applying this hunk alone makes the pinned test fail&lt;/td&gt;
&lt;td&gt;Keep it in the fix commit, one hunk at a time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;dead&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The test still passes with the hunk removed&lt;/td&gt;
&lt;td&gt;Move it to a separate cleanup pull request, or drop it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;entangled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The hunk cannot be reverse-applied on its own&lt;/td&gt;
&lt;td&gt;Inspect manually; often a rename, a move, or half of a two-part fix&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A patch whose hunks are mostly &lt;code&gt;dead&lt;/code&gt; is not wrong, it is simply over-scoped, and the table gives the contributor a defensible reason to split it before review starts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where a free model actually helps, and where it must not decide
&lt;/h2&gt;

&lt;p&gt;Once the table exists, the remaining work is interpretation: explaining why a hunk came back &lt;code&gt;entangled&lt;/code&gt;, grouping dead hunks into a coherent follow-up commit, and drafting split-commit messages that a maintainer can read in one pass. That is language work over structured evidence, which is a reasonable fit for a hosted model in a browser session.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;MonkeyCode is relevant here for one narrow reason: it advertises free model access and a free server option, both operator-supplied claims, which means a contributor can run the interpretation pass and the harness itself without paying for a subscription or provisioning a machine. The free plan page advertises a ten-million-token allowance at the time of writing, and quotas, model names, and machine specifications change often, so verify the current terms before depending on any specific number.&lt;/p&gt;

&lt;p&gt;The division of authority matters more than the tooling. The model proposes a hypothesis about an &lt;code&gt;entangled&lt;/code&gt; hunk or a commit split; the test runner remains the only thing allowed to issue a verdict. Anything the model claims about a hunk's necessity is unverified until the harness reruns and reproduces it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running the loop on a free server
&lt;/h3&gt;

&lt;p&gt;A long suite multiplies awkwardly: with &lt;em&gt;n&lt;/em&gt; hunks, the harness performs roughly &lt;em&gt;n&lt;/em&gt; + 2 full test runs. A ten-minute suite and twelve hunks is about two hours of wall-clock time, which is a poor fit for a laptop needed for other work. The free server option moves that loop off the contributor's machine and keeps the local checkout free for editing, which is the practical case for it here rather than any claim about speed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations and who should not use this
&lt;/h2&gt;

&lt;p&gt;The method has real boundaries, and a contributor who ignores them will produce a confident table that is wrong.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interacting hunks.&lt;/strong&gt; Two halves of one fix can each look &lt;code&gt;dead&lt;/code&gt; in isolation; a pairwise or grouped pass is required before deleting anything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skipped changes.&lt;/strong&gt; Header-only and mode-only changes, binary files, and pure renames fall outside the splitter and never appear in the table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flaky tests.&lt;/strong&gt; A flaky suite converts &lt;code&gt;dead&lt;/code&gt; into &lt;code&gt;load-bearing&lt;/code&gt; at random, so rerun borderline verdicts or quarantine the unstable test first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost.&lt;/strong&gt; Runtime scales linearly with hunk count, which makes the approach expensive for a fifty-hunk diff and cheap for a five-hunk one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not a correctness proof.&lt;/strong&gt; A &lt;code&gt;load-bearing&lt;/code&gt; verdict means the suite noticed the hunk, not that the fix is right or complete.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Skipping the harness is reasonable for a one-file, one-hunk patch, for repositories whose tests need privileged infrastructure the contributor cannot reproduce, and for projects whose contribution guidelines require a single squashed commit regardless of scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  A pre-push checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Confirm the pinned test fails on &lt;code&gt;HEAD&lt;/code&gt; and passes with the full patch.&lt;/li&gt;
&lt;li&gt;Split the diff into hunks and record a verdict for each one.&lt;/li&gt;
&lt;li&gt;Move every &lt;code&gt;dead&lt;/code&gt; hunk into a separate pull request, or delete it.&lt;/li&gt;
&lt;li&gt;Inspect every &lt;code&gt;entangled&lt;/code&gt; hunk by hand and note the reason in the patch description.&lt;/li&gt;
&lt;li&gt;Attach the verdict table to the pull request so the reviewer starts from evidence.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of this replaces a maintainer's judgment about design, and it is not meant to. It simply removes the cheapest objection from the review thread before anyone has to type it, which is often the difference between a patch merged this week and one reopened next month. If the loop above fits how you already work, MonkeyCode's free tier is one place to run it without a paid subscription.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>git</category>
      <category>testing</category>
      <category>ai</category>
    </item>
    <item>
      <title>Freeze the Issue Thread: Numbered Criteria Before an OSS Patch</title>
      <dc:creator>Blake Yang</dc:creator>
      <pubDate>Sun, 13 Sep 2026 19:40:35 +0000</pubDate>
      <link>https://dev.to/datars_7274/freeze-the-issue-thread-numbered-criteria-before-an-oss-patch-39a7</link>
      <guid>https://dev.to/datars_7274/freeze-the-issue-thread-numbered-criteria-before-an-oss-patch-39a7</guid>
      <description>&lt;p&gt;A first-time contributor opened a three-year-old GitHub issue with forty-seven comments and three competing workarounds. The original report described a timeout, while later comments blamed a retry helper that landed in a different module. The contributor shipped a twelve-file refactor that matched the loudest comment and missed the reproduction steps in comment eighteen. Maintainers closed the pull request as out of scope, even though the local test suite stayed green.&lt;/p&gt;

&lt;p&gt;Open-source issues rarely stay frozen after the first report, because later users paste new stacks and partial fixes. Comment order then starts to look like a specification, even though nobody voted on which workaround became canonical. A green test run on a laptop cannot prove that the change matches the issue the maintainers still intend to close. The missing artifact is a short contract that restates the thread as numbered, testable acceptance criteria.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implicit specs collapse during review
&lt;/h2&gt;

&lt;p&gt;Maintainers read a pull request against the issue title, the latest comment, and the code they remember shipping. Contributors often read the same thread as a pile of anecdotes and then patch the symptom that matched their local setup. Coding assistants amplify that mismatch when they treat the entire comment cloud as equally authoritative input. The workflow below treats the issue thread as raw material for a contract, not as a prompt dump.&lt;/p&gt;

&lt;p&gt;This pattern sits next to current debates about assistants writing entire diffs without a frozen problem statement. The failure is not that models cannot emit patches; the failure is that the issue never named the observable result. A surgical open-source patch still needs an explicit MUST list before reproduction, implementation, or review begins.&lt;/p&gt;

&lt;h3&gt;
  
  
  Failure modes the packet is meant to catch
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A workaround in a late comment silently replaces the original reproduction without maintainer confirmation.&lt;/li&gt;
&lt;li&gt;A drive-by rename lands in the same commit as the behavioral fix and hides the contract change.&lt;/li&gt;
&lt;li&gt;A test asserts an implementation detail that no comment required, so later refactors look like regressions.&lt;/li&gt;
&lt;li&gt;A model-authored summary restates the loudest comment and drops environment pins from the original report.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Build the criteria packet before any source edit
&lt;/h2&gt;

&lt;p&gt;The packet lives beside the clone, usually as &lt;code&gt;ISSUE_CONTRACT.md&lt;/code&gt;, and it is committed only if the project already stores review notes. Otherwise the file stays in the contributor's notes directory and is pasted into the pull request body as a checklist. Every MUST line must name an observable result, an environment pin, and a source comment or issue section. SHOULD and WONTFIX lines exist so the patch can refuse popular requests that maintainers already rejected.&lt;/p&gt;

&lt;p&gt;The following template is an illustrative packet, not a scraped issue from a live repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# ISSUE_CONTRACT.md&lt;/span&gt;
Issue: https://github.com/example/libretry/issues/1841
Head: main @ 9f3c1aa
Packet date: 2026-09-14

&lt;span class="gu"&gt;## MUST&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; M1. A request that times out after 200ms returns &lt;span class="sb"&gt;`Retry-Exhausted`&lt;/span&gt; without calling the deprecated &lt;span class="sb"&gt;`sleep_loop`&lt;/span&gt; helper (issue body, env: Python 3.12, Linux).
&lt;span class="p"&gt;-&lt;/span&gt; M2. &lt;span class="sb"&gt;`tests/test_retry.py`&lt;/span&gt; fails on current main with fixture &lt;span class="sb"&gt;`timeout_200ms.json`&lt;/span&gt; before the patch (comment 18).
&lt;span class="p"&gt;-&lt;/span&gt; M3. Public module &lt;span class="sb"&gt;`libretry.api`&lt;/span&gt; keeps the same exported names; &lt;span class="sb"&gt;`git diff --stat`&lt;/span&gt; stays inside &lt;span class="sb"&gt;`libretry/retry.py`&lt;/span&gt; and &lt;span class="sb"&gt;`tests/test_retry.py`&lt;/span&gt; (CONTRIBUTING.md, small diffs).

&lt;span class="gu"&gt;## SHOULD&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; S1. Log line on exhaustion includes the attempt count already used by &lt;span class="sb"&gt;`libretry.metrics`&lt;/span&gt; (comment 22, not confirmed).

&lt;span class="gu"&gt;## WONTFIX for this PR&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; W1. Rewrite the backoff to jittered exponential across all clients (comment 31, maintainer: out of scope).
&lt;span class="p"&gt;-&lt;/span&gt; W2. Rename &lt;span class="sb"&gt;`Retry-Exhausted`&lt;/span&gt; to &lt;span class="sb"&gt;`TimeoutError`&lt;/span&gt; (comment 9, closed as breaking).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Numbering rules that keep the packet honest
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Bind each MUST to a comment number, issue body section, or CONTRIBUTING rule so the source stays auditable.&lt;/li&gt;
&lt;li&gt;Record the toolchain pin in the same line as the behavior, because a laptop default is not an observable.&lt;/li&gt;
&lt;li&gt;Put popular but rejected ideas under WONTFIX so a later model review cannot revive them as helpful extras.&lt;/li&gt;
&lt;li&gt;Freeze &lt;code&gt;Head&lt;/code&gt; to a commit SHA before reproduction, so later main movement cannot silently rewrite the contract.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Reproduce against MUST lines only
&lt;/h2&gt;

&lt;p&gt;Reproduction is the first implementation of the contract, and it should fail in the way M2 describes. Clone a clean tree, check out the frozen SHA, and install the project's documented toolchain instead of the contributor's global defaults. The commands below are a labeled example for a Python library; they are not claimed as a run from a production incident.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git fetch origin main
git checkout &lt;span class="nt"&gt;--detach&lt;/span&gt; 9f3c1aa
python &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; .venv/bin/activate
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;".[test]"&lt;/span&gt;
pytest tests/test_retry.py::test_timeout_200ms &lt;span class="nt"&gt;-q&lt;/span&gt;
&lt;span class="c"&gt;# Expected on main: FAIL, matching M2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the named test does not exist yet, add a failing test that encodes M1 before any production edit. Keep that commit separate from the fix so reviewers can read failure, then repair, as two logical steps. Do not ask a model to make tests pass until M2 is visible on the frozen SHA. A passing suite at this stage means the contract is wrong, not that the project is healthy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Constrain the diff to contract paths
&lt;/h2&gt;

&lt;p&gt;Most rejected OSS patches fail review because the diff teaches the project a second lesson the issue never asked for. After M2 fails on main, create a branch whose only job is M1, and refuse files that M3 did not name. The shell snippet below is a local gate the contributor can run before every git push.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; fix/1841-retry-exhausted
&lt;span class="c"&gt;# edit only libretry/retry.py after the failing test exists&lt;/span&gt;
&lt;span class="nv"&gt;ALLOWED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'^(libretry/retry.py|tests/test_retry.py|ISSUE_CONTRACT.md)$'&lt;/span&gt;
&lt;span class="nv"&gt;bad&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git diff &lt;span class="nt"&gt;--name-only&lt;/span&gt; origin/main...HEAD | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-Ev&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ALLOWED&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$bad&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'Paths outside M3:\n%s\n'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$bad&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi
&lt;/span&gt;git diff origin/main...HEAD &lt;span class="nt"&gt;--stat&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A second commit may add S1 if the metrics log is cheap and already patterned in the code. W1 and W2 stay out of the branch even when an assistant proposes them as cleanup. Surgical diffs remain easier to revert, bisect, and backport than the comment-driven refactors that usually follow a noisy thread.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bind tests to criterion identifiers
&lt;/h2&gt;

&lt;p&gt;Reviewers should not hunt through the issue thread for the sentence that a test claims to cover. Name the test after the MUST id, and restate the observable in the assertion message. The example below is pseudocode for illustration, not a patch against a real library.&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="c1"&gt;# tests/test_retry.py
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_m1_timeout_returns_retry_exhausted_without_sleep_loop&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;ISSUE_CONTRACT M1: 200ms timeout -&amp;gt; Retry-Exhausted, no sleep_loop.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RetryClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeout_ms&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raises&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RetryExhausted&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://example.invalid/slow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sleep_loop&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;helpers_called&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;Criterion&lt;/th&gt;
&lt;th&gt;Observable&lt;/th&gt;
&lt;th&gt;Test id&lt;/th&gt;
&lt;th&gt;Allowed paths&lt;/th&gt;
&lt;th&gt;Status on frozen main&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;M1&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Retry-Exhausted&lt;/code&gt;, no &lt;code&gt;sleep_loop&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;test_m1_timeout_returns_retry_exhausted_without_sleep_loop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;libretry/retry.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;not implemented&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;M2&lt;/td&gt;
&lt;td&gt;named test fails before the fix&lt;/td&gt;
&lt;td&gt;same test on &lt;code&gt;9f3c1aa&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tests/test_retry.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;FAIL required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;M3&lt;/td&gt;
&lt;td&gt;export surface unchanged&lt;/td&gt;
&lt;td&gt;&lt;code&gt;check_issue_contract.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;those two files only&lt;/td&gt;
&lt;td&gt;gate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S1&lt;/td&gt;
&lt;td&gt;attempt count in log&lt;/td&gt;
&lt;td&gt;optional&lt;/td&gt;
&lt;td&gt;&lt;code&gt;libretry/retry.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;skip if noisy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;W1–W2&lt;/td&gt;
&lt;td&gt;no extra diff&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;git diff&lt;/code&gt; review&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;reject extras&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The small checker below walks the contract file and the merge diff. It is a local gate, not a claim about any project's CI. Save it as &lt;code&gt;check_issue_contract.py&lt;/code&gt; and treat it as a labeled example rather than a published OSS tool.&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="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="n"&gt;CONTRACT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ISSUE_CONTRACT.md&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;MUST_RE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;^- (M\d+)\. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;PATH_RE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;`([^`]+)`&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;must_ids&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&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;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;MUST_RE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;allowed_paths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&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;set&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;## MUST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;## SHOULD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;PATH_RE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;diff_names&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;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;check_output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;git&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;diff&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--name-only&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;origin/main...HEAD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splitlines&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;line&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&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;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CONTRACT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;must_ids&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No MUST ids found&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="n"&gt;pr_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PR_BODY.md&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;pr_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pr_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&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;pr_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;
    &lt;span class="n"&gt;missing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pr_body&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;missing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PR body missing MUST ids:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;allowed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;allowed_paths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ISSUE_CONTRACT.md&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PR_BODY.md&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;bad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;diff_names&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;p&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;allowed&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;bad&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Paths outside contract:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bad&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Contract ids:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Diff paths inside M3.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&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;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;python check_issue_contract.py&lt;/code&gt; after filling &lt;code&gt;PR_BODY.md&lt;/code&gt; with the same MUST list that will appear on GitHub. The script fails closed when a drive-by file appears, which is the usual review killer. It does not prove semantic correctness; it only proves the packet and the diff still talk about the same files and ids.&lt;/p&gt;

&lt;h2&gt;
  
  
  Score the diff against the packet, not against vibes
&lt;/h2&gt;

&lt;p&gt;Once M2 fails on the frozen SHA and the fix plus tests pass, the remaining risk is semantic drift. A second human pass remains the standard of record, especially for security-sensitive or cryptography-adjacent code. A model pass is useful when scored against &lt;code&gt;ISSUE_CONTRACT.md&lt;/code&gt; and the merge diff, rather than a request to improve the patch.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach. MonkeyCode's free model access can host that contract-aware review without pasting the issue thread into an ad-hoc chat window. The free server option is relevant when the review command and the project's test extras need a longer-lived workspace than a laptop session. No model name, quota, or benchmark is claimed; the workflow only needs a model that can read a diff and a packet.&lt;/p&gt;

&lt;p&gt;The review prompt below is a template for operators to adapt. It is not an executed evaluation and it is not a ranking of products.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are scoring a patch against ISSUE_CONTRACT.md.
Read the contract first, then the git diff.
For each MUST id, answer: satisfied / violated / not evidenced.
For each WONTFIX id, answer: absent / revived.
List files in the diff that the contract did not allow.
Do not suggest extra refactors, renames, or dependency bumps.
If the diff includes files outside M3, fail the review.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep that prompt next to the packet so the same words gate both the human description and the model pass. Contributors can run the same prompt against MonkeyCode's free model access when they want a second reader that cannot invent new scope. The packet still works if that second reader is a teammate instead of a hosted model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision table for common issue shapes
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Issue shape&lt;/th&gt;
&lt;th&gt;Contract emphasis&lt;/th&gt;
&lt;th&gt;Patch allowed to touch&lt;/th&gt;
&lt;th&gt;Model review question&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Timeout or retry bug&lt;/td&gt;
&lt;td&gt;environment pin plus exact exception&lt;/td&gt;
&lt;td&gt;one module and one test&lt;/td&gt;
&lt;td&gt;Did the deprecated helper return in traces?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docs versus behavior mismatch&lt;/td&gt;
&lt;td&gt;quote the documented example&lt;/td&gt;
&lt;td&gt;docs file or code, not both unless M1 says so&lt;/td&gt;
&lt;td&gt;Which side is canonical in CONTRIBUTING?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Closed WONTFIX revived by users&lt;/td&gt;
&lt;td&gt;WONTFIX list copied from maintainer comment&lt;/td&gt;
&lt;td&gt;no files, or an issue comment only&lt;/td&gt;
&lt;td&gt;Did the diff revive W1?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CI-only failure&lt;/td&gt;
&lt;td&gt;job name, image tag, and seed&lt;/td&gt;
&lt;td&gt;CI config plus the failing test&lt;/td&gt;
&lt;td&gt;Was the local command the same as CI?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The table is a planning tool for triage, not a complete taxonomy of every issue shape. If an issue mixes a public API break with a private helper change, split it into two packets and two pull requests. Mixing those concerns is how comment eighteen disappears under a rename that no MUST line requested.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;This workflow assumes the issue thread contains at least one reproduction hint and one maintainer signal about scope. It will not invent a root cause for a crash that nobody on the thread can trigger. The path gate cannot see semantic breakage inside an allowed file, so M1 still needs a real assertion. Automated model review will still miss domain invariants that the written contract forgot to capture in MUST form.&lt;/p&gt;

&lt;p&gt;The checker also trusts &lt;code&gt;origin/main...HEAD&lt;/code&gt;, which is wrong for stacked branches or for repositories whose default branch is not &lt;code&gt;main&lt;/code&gt;. Teams that squash every commit still need the failing test visible in review, even if history becomes one commit later. None of the examples above are performance claims, and none should be copied into a security advisory without a separate process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should skip this workflow
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Drivers who already have a maintainer-written design doc should follow that doc rather than re-deriving MUST lines from noisy comments.&lt;/li&gt;
&lt;li&gt;Emergency incident patches that need to land in minutes cannot afford a packet ceremony and should use a revert or a feature flag.&lt;/li&gt;
&lt;li&gt;Contributors who cannot run the project's tests at all should not use a model review as a substitute for reproduction.&lt;/li&gt;
&lt;li&gt;People looking for a fully automated issue-to-merge agent will not find that here, because the contract is a human freeze.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What maintainers see
&lt;/h2&gt;

&lt;p&gt;A pull request that pastes the packet and shows M2 failing on the named SHA is easier to trust than a restated comment. The follow-up commit should show M1 passing on the branch with the same identifiers in the test names. The diffstat matches M3, WONTFIX items stay absent, and the citations still point at issue comments. That packet is the original artifact; the optional model score is only a second reader with the same sheet.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>git</category>
      <category>testing</category>
      <category>ai</category>
    </item>
    <item>
      <title>Ship a One-Command Repro Script Before Maintainers Read an OSS Diff</title>
      <dc:creator>Blake Yang</dc:creator>
      <pubDate>Sat, 12 Sep 2026 17:35:58 +0000</pubDate>
      <link>https://dev.to/datars_7274/ship-a-one-command-repro-script-before-maintainers-read-an-oss-diff-2cb7</link>
      <guid>https://dev.to/datars_7274/ship-a-one-command-repro-script-before-maintainers-read-an-oss-diff-2cb7</guid>
      <description>&lt;p&gt;A contributor pasted a twelve-file diff under an issue that described a CLI exiting zero on invalid UTF-8 input. The maintainer cloned the fork on a clean runner and could not trigger the failure with the commands in the description. Three review comments later, the conversation still concerned local virtualenvs, Python minor versions, and a fixture that never reached the repository. The patch may have been correct, yet the project had no command a stranger could run to watch the bug happen.&lt;/p&gt;

&lt;p&gt;Open-source review stalls when the reproduction lives only in the author's shell history. Maintainers need a script that fails on the reported revision, passes after the patch, and names every environment assumption in plain text. This article records that packet as a review artifact, then shows how a free-tier model pass can check issue-to-command traceability without rewriting the patch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treat the Issue as a Contract, Not as Flavor Text
&lt;/h2&gt;

&lt;p&gt;Issue templates already collect version strings, operating systems, install steps, and expected versus actual output. Contributors often skip that structure and jump into a refactor that also happens to mention the bug. The safer order is to freeze a reproduction contract before any production file changes, then refuse to expand the diff until that contract fails on current &lt;code&gt;HEAD&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The contract is a short table, not a narrative. Each row must be something a maintainer can execute without guessing paths or secrets. Rows that cannot be turned into a command do not belong in the first patch.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Contract field&lt;/th&gt;
&lt;th&gt;Example freeze&lt;/th&gt;
&lt;th&gt;Reject if missing&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Upstream revision&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;git rev-parse HEAD&lt;/code&gt; at clone time&lt;/td&gt;
&lt;td&gt;"latest main" with no SHA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtime&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;python3.12&lt;/code&gt; from the project's documented range&lt;/td&gt;
&lt;td&gt;Author's private conda env&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input&lt;/td&gt;
&lt;td&gt;&lt;code&gt;printf '\xff' &amp;gt; /tmp/bad.bin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;"a weird file I have locally"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Command&lt;/td&gt;
&lt;td&gt;&lt;code&gt;./cli parse /tmp/bad.bin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;IDE click-path only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Actual now&lt;/td&gt;
&lt;td&gt;exit &lt;code&gt;0&lt;/code&gt; and empty stderr&lt;/td&gt;
&lt;td&gt;screenshot without exit code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Expected after patch&lt;/td&gt;
&lt;td&gt;exit &lt;code&gt;2&lt;/code&gt; and &lt;code&gt;invalid utf-8&lt;/code&gt; on stderr&lt;/td&gt;
&lt;td&gt;"should feel more correct"&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Copy that table into &lt;code&gt;REPRO.md&lt;/code&gt; beside the future patch. Do not describe hoped-for architecture in this file. Architecture notes wait until the command fails for a stranger.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build a Maintainer-Shaped Script Before Touching Library Code
&lt;/h2&gt;

&lt;p&gt;A reproduction script should pin the revision, create an isolated directory, install only documented extras, and exit non-zero while the bug still exists. The script is the first commit on the contribution branch, even when the production fix is still unknown. Maintainers can then run one command on the author's branch and on &lt;code&gt;main&lt;/code&gt; without reading the diff.&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="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# repro.sh — must fail on the buggy revision, pass after the fix.&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;ROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;REV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;REV&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ROOT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; rev-parse HEAD&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;WORKDIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;mktemp&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; /tmp/oss-repro.XXXXXX&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;trap&lt;/span&gt; &lt;span class="s1"&gt;'rm -rf "$WORKDIR"'&lt;/span&gt; EXIT

git &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ROOT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; archive &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$REV&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$WORKDIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$WORKDIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

python3.12 &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv
&lt;span class="c"&gt;# shellcheck disable=SC1091&lt;/span&gt;
&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
python &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;".[dev]"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/tmp/repro-install.log

&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'\xff'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/bad.bin
&lt;span class="nb"&gt;set&lt;/span&gt; +e
./.venv/bin/cli parse /tmp/bad.bin &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/tmp/repro-out.txt 2&amp;gt;/tmp/repro-err.txt
&lt;span class="nv"&gt;STATUS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"rev=&lt;/span&gt;&lt;span class="nv"&gt;$REV&lt;/span&gt;&lt;span class="s2"&gt; exit=&lt;/span&gt;&lt;span class="nv"&gt;$STATUS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$STATUS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"BUG STILL PRESENT: invalid input was accepted"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi
&lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="s1"&gt;'invalid utf-8'&lt;/span&gt; /tmp/repro-err.txt
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"repro satisfied"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mark the script executable and run it against the issue revision before writing a fix. The first run should print &lt;code&gt;BUG STILL PRESENT&lt;/code&gt; and exit &lt;code&gt;1&lt;/code&gt;. If it prints &lt;code&gt;repro satisfied&lt;/code&gt; on &lt;code&gt;main&lt;/code&gt;, the issue is already fixed or the contract is wrong, and no library patch should ship.&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="nb"&gt;chmod&lt;/span&gt; +x repro.sh
git switch &lt;span class="nt"&gt;-c&lt;/span&gt; fix/invalid-utf8-exit-code
git add repro.sh REPRO.md
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"test: add maintainer repro for invalid UTF-8 exit code"&lt;/span&gt;
&lt;span class="nv"&gt;REV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git rev-parse HEAD&lt;span class="si"&gt;)&lt;/span&gt; ./repro.sh&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"first-run exit=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep generated virtualenvs and &lt;code&gt;/tmp&lt;/code&gt; fixtures out of git. The script creates those paths on each run so reviewers do not inherit the author's machine. If the project needs a compiler flag or a locale, put that export in the script rather than in a blog comment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fail the Same Assertion in the Project Test Runner
&lt;/h2&gt;

&lt;p&gt;A shell repro is necessary for maintainers who will not open an IDE. It is not a substitute for the suite that CI already knows how to execute. After the script fails, add one test in the project's normal layout that encodes the same input, command, and exit contract.&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="c1"&gt;# tests/test_invalid_utf8_exit.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_parse_rejects_invalid_utf8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tmp_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tmp_path&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bad.bin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write_bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\xff&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;proc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-m&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cli&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;parse&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
        &lt;span class="n"&gt;capture_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;returncode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;invalid utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run that file alone until it fails for the documented reason, not for an import error. Import failures mean the repro still depends on unpublished helpers. Only then is a production edit in scope.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; pytest tests/test_invalid_utf8_exit.py &lt;span class="nt"&gt;-q&lt;/span&gt;
&lt;span class="c"&gt;# expected on main: 1 failed, assertion on returncode or stderr&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Patch Against the Contract, Then Re-run Both Gates
&lt;/h2&gt;

&lt;p&gt;Limit the production change to the code path the repro actually exercises. Wide cleanups belong on a later branch after the bug is closed. After the edit, the same &lt;code&gt;repro.sh&lt;/code&gt; must invert its meaning: the bug-present branch of the script should no longer trigger, and the pytest file should pass in isolation and with the project's default target.&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="c"&gt;# after the smallest library edit&lt;/span&gt;
./repro.sh &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; python &lt;span class="nt"&gt;-m&lt;/span&gt; pytest tests/test_invalid_utf8_exit.py &lt;span class="nt"&gt;-q&lt;/span&gt;
git add src/cli/parse.py tests/test_invalid_utf8_exit.py
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"fix: reject invalid UTF-8 with exit 2"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;repro.sh&lt;/code&gt; still exits &lt;code&gt;1&lt;/code&gt;, the patch did not implement the contract, even if unit tests elsewhere turned green. If pytest passes while &lt;code&gt;repro.sh&lt;/code&gt; fails, the suite is mocking away the install path maintainers will use. Both results block the pull request until they agree.&lt;/p&gt;

&lt;h2&gt;
  
  
  Map Each Issue Sentence to a Hunk Before Asking for Review
&lt;/h2&gt;

&lt;p&gt;Maintainers reject AI-shaped patches when the diff argues with the issue. A mapping file prevents that drift. Write &lt;code&gt;REVIEW_MAP.md&lt;/code&gt; with one bullet per issue claim, the command that witnesses it, and the file hunk that implements it. Claims without a command stay out of the pull request body.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# REVIEW_MAP.md&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Claim: invalid byte sequence must not exit 0
  Witness: &lt;span class="sb"&gt;`./repro.sh`&lt;/span&gt; on this branch exits 0 after the fix commit
  Hunk: &lt;span class="sb"&gt;`src/cli/parse.py`&lt;/span&gt; decoder error path
&lt;span class="p"&gt;-&lt;/span&gt; Claim: stderr names the encoding failure
  Witness: &lt;span class="sb"&gt;`grep -q 'invalid utf-8' /tmp/repro-err.txt`&lt;/span&gt;
  Hunk: &lt;span class="sb"&gt;`src/cli/parse.py`&lt;/span&gt; error formatter
&lt;span class="p"&gt;-&lt;/span&gt; Non-claim: no public CLI flag renamed in this patch
  Witness: &lt;span class="sb"&gt;`git diff main -- src/cli/flags.py`&lt;/span&gt; is empty
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A second reader can check that mapping without touching the working tree. Disclosure: This article was prepared as part of MonkeyCode's product outreach. Contributors who already use MonkeyCode's free model access and free server option can paste the issue text, &lt;code&gt;repro.sh&lt;/code&gt;, and the unified diff into that workspace and ask only whether each claim has a failing-then-passing command. The workflow does not depend on that product, and this article does not add model names, quotas, or hardware claims beyond those two operator-supplied options.&lt;/p&gt;

&lt;p&gt;Keep the model prompt narrow so it cannot invent extra refactors. The useful question is whether the packet is internally consistent, not whether the code looks stylish.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are checking a maintainer reproduction packet.
Do not propose new features or drive-by cleanups.
Issue text, REPRO.md, repro.sh, REVIEW_MAP.md, and git diff follow.
List every issue claim that lacks a command or a hunk.
List every diff hunk that matches no issue claim.
If the script would pass on the buggy revision, say so explicitly.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Treat the model output as a checklist against &lt;code&gt;REVIEW_MAP.md&lt;/code&gt;. If it reports an unmatched hunk, delete that hunk or move it to a follow-up issue. If it reports a missing witness, extend &lt;code&gt;repro.sh&lt;/code&gt; instead of arguing in prose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision Table for Stopping Work
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Observation&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Do not&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;repro.sh&lt;/code&gt; passes on &lt;code&gt;main&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Close as already fixed or rewrite the contract&lt;/td&gt;
&lt;td&gt;Ship a speculative cleanup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Script fails on missing compiler&lt;/td&gt;
&lt;td&gt;Record the toolchain in &lt;code&gt;REPRO.md&lt;/code&gt; and the script&lt;/td&gt;
&lt;td&gt;Ask maintainers to "use my laptop"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pytest green, script red&lt;/td&gt;
&lt;td&gt;Drop mocks that hide install layout&lt;/td&gt;
&lt;td&gt;Trust local IDE runners&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model flags an extra hunk&lt;/td&gt;
&lt;td&gt;Revert that hunk before review&lt;/td&gt;
&lt;td&gt;Explain the extra hunk in the PR essay&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contract needs network or secrets&lt;/td&gt;
&lt;td&gt;Split into a follow-up with documented credentials&lt;/td&gt;
&lt;td&gt;Put tokens in the repro script&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Limitations and Who Should Skip This Packet
&lt;/h2&gt;

&lt;p&gt;The one-command packet assumes the bug is deterministic, local, and expressible as process input plus exit status or files. Timing races, GPU kernels, and hardware-specific faults need a different harness, often with logging and multiple iterations. This workflow also assumes the project already documents an install path that a clean checkout can follow.&lt;/p&gt;

&lt;p&gt;Contributors should not use this packet as a replacement for the project's required CI jobs. A green &lt;code&gt;repro.sh&lt;/code&gt; on one Python minor version does not prove the matrix the maintainers actually ship. People working on security issues with non-public fixtures should keep those fixtures out of a public &lt;code&gt;repro.sh&lt;/code&gt; and follow the project's private disclosure process instead.&lt;/p&gt;

&lt;p&gt;Teams that already have a hermetic &lt;code&gt;nix develop&lt;/code&gt; or container entrypoint can wrap that entrypoint rather than inventing a second installer. The artifact that matters is still a single command whose exit code flips with the patch. Free model review of the mapping is optional and can be skipped when the packet is shorter than a screen.&lt;/p&gt;

&lt;p&gt;The pull request body then stays short: link the issue, paste the one command, and attach &lt;code&gt;REVIEW_MAP.md&lt;/code&gt;. Maintainers can reproduce before they argue about style. Contributors who already keep a free coding workspace can run the same packet there as optional verification, then still wait for the project's own runner before claiming the bug is gone.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>testing</category>
      <category>git</category>
      <category>ai</category>
    </item>
    <item>
      <title>Worktree Isolation for OSS Bugs: A Review Packet Maintainers Can Trust</title>
      <dc:creator>Blake Yang</dc:creator>
      <pubDate>Fri, 11 Sep 2026 15:22:50 +0000</pubDate>
      <link>https://dev.to/datars_7274/worktree-isolation-for-oss-bugs-a-review-packet-maintainers-can-trust-1mjc</link>
      <guid>https://dev.to/datars_7274/worktree-isolation-for-oss-bugs-a-review-packet-maintainers-can-trust-1mjc</guid>
      <description>&lt;p&gt;On a typical issue tracker, a contributor clones a small HTTP client and treats a timeout as a one-line constant change. The pull request description cites a single local test run on the newest interpreter the laptop already had installed. Continuous integration then fails on an older runtime the contributor never installed, and the thread spends days reconstructing a reproduction. Maintainers are not rejecting the idea of a fix; they are rejecting a change that never isolated the failing command.&lt;/p&gt;

&lt;p&gt;Public discussion around AI coding tools often frames models as ready to emit complete patches from a full repository dump. That framing skips the part of open source work that still fails in practice: proving the bug, constraining the diff, and showing one command before and after. A model that reads an entire tree will invent helpers, ignore matrix cells, and rewrite style the project does not use. A smaller packet built inside an isolated git worktree gives both humans and models the same evidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Whole-repo pastes hide the failure
&lt;/h2&gt;

&lt;p&gt;Open source reviews fail for mechanical reasons that have little to do with model quality or contributor intent. The reviewer cannot see which command actually failed, which files were incidental, or which contributing rules the author actually read. A paste of the repository also hides generated lockfiles, vendored snapshots, and local configuration that should never leave the laptop.&lt;/p&gt;

&lt;p&gt;A useful packet answers four points with files rather than adjectives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which worktree and commit reproduced the bug in isolation&lt;/li&gt;
&lt;li&gt;Which exact command failed, including arguments and exit status&lt;/li&gt;
&lt;li&gt;Which files the patch actually touches, shown as a unified diff&lt;/li&gt;
&lt;li&gt;Which project rules constrain the change, quoted from tests or CONTRIBUTING&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rest of this article proposes a workflow. Commands are examples for a typical Python library and should be adapted to the target project's documented test runner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Isolate the bug in a throwaway worktree
&lt;/h2&gt;

&lt;p&gt;Cloning a second full copy is slower than git worktree, and a second worktree keeps failed experiments off the main checkout. The contributor should start from the revision named in the issue, not from a personal branch that already contains unrelated formatting. A clean tree makes later diffs honest, because generated files from a previous attempt will not leak into the patch.&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="c"&gt;# Proposed workflow — adapt paths and the issue SHA to the target repository.&lt;/span&gt;
git fetch origin
git worktree add ../repro-issue-1842 origin/main
&lt;span class="nb"&gt;cd&lt;/span&gt; ../repro-issue-1842
git switch &lt;span class="nt"&gt;-c&lt;/span&gt; repro/issue-1842
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the issue names a tag or a commit, check that revision out before installing dependencies so the failing command matches the report. Project docs, not a model guess, should decide how extras and test tools are installed.&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="c"&gt;# Example only: pin the reported revision, then install from the project docs.&lt;/span&gt;
git checkout &lt;span class="nt"&gt;--detach&lt;/span&gt; 7c1a9e4
python &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv
&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;".[dev]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Capture the failing command as the contract
&lt;/h2&gt;

&lt;p&gt;A stack trace in an issue comment is not a contract. The contract is a command that exits non-zero in this worktree and will be re-run after the patch. Write that command into a file so later review, CI, and any model see the same bytes.&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="c"&gt;# Proposed capture: store stdout, stderr, and the exit code beside the tree.&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; .repro
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\n'&lt;/span&gt; &lt;span class="s1"&gt;'python -m pytest tests/test_retry.py::test_timeout_default -q'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .repro/failing_cmd.sh
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x .repro/failing_cmd.sh
&lt;span class="nb"&gt;set&lt;/span&gt; +e
.repro/failing_cmd.sh &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .repro/before.txt 2&amp;gt;&amp;amp;1
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .repro/before.exit
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; .repro/before.exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the exit file does not contain a non-zero status, stop immediately. The environment does not yet reproduce the bug, and a patch would be guesswork. Common misses include the wrong extra, a missing locale, and a test that only fails under a specific language minor version.&lt;/p&gt;

&lt;p&gt;Truncate the log before anyone pastes it into a review tool. Long traces bury the assertion, and remote reviewers should not need the full pip wheel noise.&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="c1"&gt;# Proposed helper: keep the packet readable.
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="n"&gt;LIMIT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
&lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.repro/before.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;replace&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;splitlines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.repro/before.tail.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;write_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;LIMIT&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&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;h2&gt;
  
  
  Keep the patch inside the failing command's neighborhood
&lt;/h2&gt;

&lt;p&gt;Once the command fails, search only the modules that command imported. A model asked to fix retries will often rewrite the public client class, add a helper the suite never calls, or change default arguments that other tests rely on. The human author should produce the smallest diff that turns the captured command green.&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="c"&gt;# Example investigation commands, not a diagnosis of any real project.&lt;/span&gt;
python &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'from retry_client import Client; print(Client.__module__)'&lt;/span&gt;
git &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"timeout"&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"*.py"&lt;/span&gt;
git &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"def test_timeout_default"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After editing, re-run the same script without changing its arguments. If unrelated files appear in &lt;code&gt;git diff --stat&lt;/code&gt;, reset them before the packet is built. Formatters that touch the whole tree belong in a separate commit, and only when the project already requires that formatter in CI.&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="nb"&gt;set&lt;/span&gt; +e
.repro/failing_cmd.sh &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .repro/after.txt 2&amp;gt;&amp;amp;1
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .repro/after.exit
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt;
&lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; .repro/after.exit&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"0"&lt;/span&gt;
git diff &lt;span class="nt"&gt;--stat&lt;/span&gt;
git diff &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"*.py"&lt;/span&gt; &lt;span class="s2"&gt;"tests/*.py"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A second local command is worth running when the project already documents it: the unit node that failed, then the nearest file or folder that guards regressions. Expanding to the full suite too early hides the original contract inside unrelated noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build a review packet instead of uploading the tree
&lt;/h2&gt;

&lt;p&gt;The packet is a single markdown file plus the unified diff. It should be small enough to read in one sitting and free of secrets, absolute home paths, and vendor directories. Optionally append short quotes from &lt;code&gt;CONTRIBUTING.md&lt;/code&gt;, the issue's acceptance comments, and the project's test matrix file.&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="c"&gt;# Proposed packet builder. Review the output before any remote upload.&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"# Review packet for issue 1842"&lt;/span&gt;
  &lt;span class="nb"&gt;echo
  echo&lt;/span&gt; &lt;span class="s2"&gt;"## Reproduction"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"- commit: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git rev-parse HEAD&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"- command: &lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="s1"&gt;'\n'&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; &amp;lt; .repro/failing_cmd.sh&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="se"&gt;\`&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"- exit before: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; .repro/before.exit&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"- exit after: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; .repro/after.exit&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;echo
  echo&lt;/span&gt; &lt;span class="s2"&gt;"## Failing command output (truncated)"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'```

'&lt;/span&gt;
  &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 80 .repro/before.txt
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'

```'&lt;/span&gt;
  &lt;span class="nb"&gt;echo
  echo&lt;/span&gt; &lt;span class="s2"&gt;"## Diff"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'```

diff'&lt;/span&gt;
  git diff &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"*.py"&lt;/span&gt; &lt;span class="s2"&gt;"tests/*.py"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'

```'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .repro/REVIEW_PACKET.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not paste entire policy documents into the packet. A model that receives twenty pages of contributing guide will ignore the one rule that matters, such as no new runtime dependencies. Quote the rule in one block, then keep the rest of the file mechanical.&lt;/p&gt;

&lt;h3&gt;
  
  
  Files that must stay out of the packet
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.env&lt;/code&gt;, tokens, cookie jars, and editor settings&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;node_modules&lt;/code&gt;, &lt;code&gt;.venv&lt;/code&gt;, &lt;code&gt;vendor&lt;/code&gt;, and built wheels&lt;/li&gt;
&lt;li&gt;Unrelated dirty files from a formatter or a failed rebase&lt;/li&gt;
&lt;li&gt;The full git object store; the worktree diff is enough&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Decision table: what a model is allowed to do
&lt;/h2&gt;

&lt;p&gt;This table is the working artifact of the workflow. The model does not replace the test runner, and it does not replace the project's hosted CI. It reviews a bounded packet after the failing command has already turned green.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Packet section&lt;/th&gt;
&lt;th&gt;Human owner&lt;/th&gt;
&lt;th&gt;Model role&lt;/th&gt;
&lt;th&gt;Reject if&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Failing command&lt;/td&gt;
&lt;td&gt;Contributor&lt;/td&gt;
&lt;td&gt;May suggest a narrower test node id&lt;/td&gt;
&lt;td&gt;The command was never run locally&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Diff&lt;/td&gt;
&lt;td&gt;Contributor&lt;/td&gt;
&lt;td&gt;Review only: style, missing tests, API breakage&lt;/td&gt;
&lt;td&gt;The model authors files not in the packet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CONTRIBUTING quotes&lt;/td&gt;
&lt;td&gt;Contributor&lt;/td&gt;
&lt;td&gt;Check the diff against quoted rules&lt;/td&gt;
&lt;td&gt;The quote is paraphrased from memory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CI matrix note&lt;/td&gt;
&lt;td&gt;Contributor&lt;/td&gt;
&lt;td&gt;Flag untested runtimes&lt;/td&gt;
&lt;td&gt;The model claims a matrix cell passed without a log&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Treat any suggested patch from the model as a comment, not as a commit. Re-run &lt;code&gt;.repro/failing_cmd.sh&lt;/code&gt; after every accepted edit, even when the comment looks purely stylistic. Style-only rewrites still break public signatures in libraries with downstream users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where a free model and a free server fit
&lt;/h2&gt;

&lt;p&gt;Some contributors cannot install every CI runtime on a laptop, and some want a second pass on the packet before the pull request. Disclosure: This article was prepared as part of MonkeyCode's product outreach. MonkeyCode offers free model access and a free server option, which can re-run the captured command and return comments on &lt;code&gt;REVIEW_PACKET.md&lt;/code&gt; rather than on a full repository archive. Contributors who already have a green local command can use that optional remote pass, then still wait for the project's hosted CI before pinging maintainers.&lt;/p&gt;

&lt;p&gt;The useful split stays strict. The server re-runs &lt;code&gt;.repro/failing_cmd.sh&lt;/code&gt; in a clean environment. The model receives the packet and returns a review, not a rewritten tree. If the remote command disagrees with the local exit codes, the packet is incomplete and the pull request should wait.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations and who should skip this
&lt;/h2&gt;

&lt;p&gt;The workflow does not claim that a free server matches every OS, libc, or language version in a project's matrix. It does not verify performance, concurrency, or network flakiness that only appears under load. Models still invent APIs that look plausible in a diff comment and still miss license headers the project requires.&lt;/p&gt;

&lt;p&gt;Skip this approach in the following cases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The bug is under a security embargo, or the fixture contains production data.&lt;/li&gt;
&lt;li&gt;Reproduction needs hardware or licensed runtimes the remote environment cannot provide.&lt;/li&gt;
&lt;li&gt;The change is a documentation typo that never needed a model or a second server.&lt;/li&gt;
&lt;li&gt;The contributor cannot compare the model's review against the actual test log.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A review packet is extra ceremony for a one-character fix in a personal script. It earns its keep on libraries with downstream users, public APIs, and CI matrices that a laptop will not cover. It also fails closed: if the captured command never failed, there is no patch to review, and if the packet includes secrets or the entire tree, the remote step should not run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing sequence
&lt;/h2&gt;

&lt;p&gt;The sequence is isolate, capture, patch, packet, then optional remote review. Maintainers can re-run one command and read one diff without reconstructing the author's laptop. Models stay useful when they are downstream of evidence, not when they are asked to invent the evidence from a repository zip. Those two stops prevent the most common failure in AI-assisted open source work: a fluent diff that never reproduced the bug.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>git</category>
      <category>testing</category>
      <category>ai</category>
    </item>
    <item>
      <title>Last Green Tag First: Bisect an OSS Regression Before the Patch Review</title>
      <dc:creator>Blake Yang</dc:creator>
      <pubDate>Thu, 10 Sep 2026 04:19:16 +0000</pubDate>
      <link>https://dev.to/datars_7274/last-green-tag-first-bisect-an-oss-regression-before-the-patch-review-4l0a</link>
      <guid>https://dev.to/datars_7274/last-green-tag-first-bisect-an-oss-regression-before-the-patch-review-4l0a</guid>
      <description>&lt;p&gt;A mid-size Python CLI received an issue that empty &lt;code&gt;HTTP_PROXY&lt;/code&gt; values were now being sent to child processes as blank strings. A well-meaning contributor asked a coding model for a patch and received a thirty-line rewrite of the process launcher. The pull request looked clean in the diffstat, yet it also changed timeout handling that had been stable since the &lt;code&gt;v3.2.0&lt;/code&gt; tag. Maintainers closed the PR after a reviewer traced the real regression to a one-line defaulting change in a logging helper.&lt;/p&gt;

&lt;p&gt;That pattern is now common in open-source inboxes, because models optimize for the symptom in the issue title. They rarely search for the first commit that changed documented behavior on a tagged release. A cheaper sequence is mechanical: prove the last release green, prove &lt;code&gt;HEAD&lt;/code&gt; red, then bisect to one commit. Only after that pin should any model be invited to propose or review a patch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treat the last release tag as the control group
&lt;/h2&gt;

&lt;p&gt;Issue templates rarely state which release last worked for the reporter, so contributors patch &lt;code&gt;HEAD&lt;/code&gt; as if the entire tree were guilty. Maintainers then pay for that guesswork during review, because unrelated helpers get rewritten in the name of safety. A tagged control group makes the claim falsifiable for anyone who can install the test extra. If the last tag already fails the oracle, the report is not a regression and the patch needs a different contract.&lt;/p&gt;

&lt;p&gt;The control group also keeps a later model review inside a small packet of evidence. A coding model that never sees the blamed commit will invent architecture around the issue title. The bisect log is a short, citable artifact that can travel with the pull request. Reviewers can replay it without inheriting a dirty local worktree or a half-applied virtualenv.&lt;/p&gt;

&lt;h2&gt;
  
  
  Worked example: empty proxy values
&lt;/h2&gt;

&lt;p&gt;The files below are a labeled worked example, not a claim about any production codebase. The documented CLI contract treats a missing or empty &lt;code&gt;HTTP_PROXY&lt;/code&gt; as unset for child processes. After a commit that “simplified defaults,” empty strings started leaking into &lt;code&gt;subprocess&lt;/code&gt; environments. An oracle that fails for that reason alone keeps the later patch inside one function.&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="c1"&gt;# proj/envutil.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Mapping&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;child_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;overrides&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Mapping&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&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;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Build an env dict for child processes.

    Empty values are treated as unset, matching the v3.2 CLI contract.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&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;v&lt;/span&gt; &lt;span class="o"&gt;!=&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;overrides&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;overrides&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&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;value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&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;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# tests/oracle_empty_proxy.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;proj.envutil&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;child_env&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_empty_http_proxy_is_unset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;monkeypatch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;monkeypatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HTTP_PROXY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;child_env&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HTTP_PROXY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_missing_http_proxy_stays_missing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;monkeypatch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;monkeypatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HTTP_PROXY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raising&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;child_env&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HTTP_PROXY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A contributor who starts from the issue text might wrap the whole launcher in extra filtering. The oracle above fails for one contract only, which is the point of the control group. Neighboring timeout helpers stay out of the diff until bisect says they belong there. Maintainers can read the oracle in a minute and know what “fixed” is supposed to mean.&lt;/p&gt;

&lt;h2&gt;
  
  
  A maintainer-runnable bisect script
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;git bisect run&lt;/code&gt; needs a deterministic exit code from a script that does not care about chat history. Exit &lt;code&gt;0&lt;/code&gt; means the bug is absent, exit &lt;code&gt;1&lt;/code&gt; means the bug is present, and exit &lt;code&gt;125&lt;/code&gt; means the tree cannot be tested. Any other code aborts the search and leaves reviewers with a half-finished log. The script below is meant to live on the topic branch, or to be pasted into the pull request body.&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="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# scripts/bisect-repro.sh&lt;/span&gt;
&lt;span class="c"&gt;# Worked example: replayable oracle for an empty-proxy regression.&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;ROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/.."&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ROOT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; pyproject.toml &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; setup.cfg &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; setup.py &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"skip: Python project metadata missing in this commit"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
  &lt;span class="nb"&gt;exit &lt;/span&gt;125
&lt;span class="k"&gt;fi

&lt;/span&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;".[dev]"&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;125

&lt;span class="c"&gt;# Isolate the oracle from the rest of a possibly red suite.&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; pytest &lt;span class="nt"&gt;-q&lt;/span&gt; tests/oracle_empty_proxy.py&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;span class="k"&gt;fi
&lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Record the control group, then search toward HEAD.&lt;/span&gt;
git fetch &lt;span class="nt"&gt;--tags&lt;/span&gt; &lt;span class="nt"&gt;--prune&lt;/span&gt;
git checkout v3.2.0
bash scripts/bisect-repro.sh    &lt;span class="c"&gt;# must exit 0; otherwise this is not a regression&lt;/span&gt;

git checkout main
bash scripts/bisect-repro.sh    &lt;span class="c"&gt;# must exit 1; otherwise the bug is not on HEAD&lt;/span&gt;

git bisect start
git bisect bad HEAD
git bisect good v3.2.0
git bisect run bash scripts/bisect-repro.sh
git bisect log &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; bisect.log
git bisect reset
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;125&lt;/code&gt; skip path matters on real repositories, where merge commits and missing extras would otherwise be labeled good. A skipped commit keeps the search honest instead of poisoning the good set with an unbuildable tree. After the pin, &lt;code&gt;git show --stat&lt;/code&gt; on the blamed SHA and &lt;code&gt;git tag --contains&lt;/code&gt; tell reviewers which releases already shipped the fault. Those two commands belong in the pull request body beside &lt;code&gt;bisect.log&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision table for when a model may review
&lt;/h2&gt;

&lt;p&gt;The table is the workflow gate, not a style preference for commit messages. If a row says the model stays out, the contributor keeps gathering evidence instead of drafting a rewrite. Tokens are still wasted when the blamed commit is unknown and the oracle is not replayable. Maintainers can apply the same rows without reading any chat transcript.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Observation after the oracle&lt;/th&gt;
&lt;th&gt;What to do next&lt;/th&gt;
&lt;th&gt;Model review allowed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Last tag fails the oracle&lt;/td&gt;
&lt;td&gt;Not a regression; write a characterization test instead&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;HEAD&lt;/code&gt; passes the oracle&lt;/td&gt;
&lt;td&gt;Cannot reproduce; freeze locale, cwd, and fixture paths&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Oracle is flaky on the same commit&lt;/td&gt;
&lt;td&gt;Fix seed, time, and network before any search&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bisect lands on a merge commit&lt;/td&gt;
&lt;td&gt;Bisect the merged topic branch by parent&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pin is one function in one file&lt;/td&gt;
&lt;td&gt;Draft a minimal patch against that hunk&lt;/td&gt;
&lt;td&gt;Yes, scoped packet only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pin touches generated code or lockfiles&lt;/td&gt;
&lt;td&gt;Re-run codegen; do not hand-edit the artifact&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pin is a dependency bump&lt;/td&gt;
&lt;td&gt;Read the upstream changelog; consider pinning&lt;/td&gt;
&lt;td&gt;Changelog only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Most rejected AI patches fail the first three rows and still look productive in a chat window. The pull request then arrives without a replayable pin, so reviewers repeat the archaeology. The boring gate is the feature: it names the moment when a model is allowed to speak. Until that row is reached, the only artifacts that matter are the oracle and the bisect log.&lt;/p&gt;

&lt;h2&gt;
  
  
  Draft the patch against the blamed commit
&lt;/h2&gt;

&lt;p&gt;Once bisect names a commit, the patch should restore the documented contract with the smallest hunk that makes the oracle pass. Drive-by refactors in neighboring helpers should stay out of that commit, even when a model offers them as cleanup. &lt;code&gt;git range-diff&lt;/code&gt; helps when two drafts rewrite the same idea, because it shows whether the second draft still targets the blamed lines. The topic branch can start from &lt;code&gt;main&lt;/code&gt; while the PR body still cites the pin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; fix/empty-http-proxy main

&lt;span class="c"&gt;# After editing proj/envutil.py, keep the oracle green and the suite green.&lt;/span&gt;
python &lt;span class="nt"&gt;-m&lt;/span&gt; pytest &lt;span class="nt"&gt;-q&lt;/span&gt; tests/oracle_empty_proxy.py
python &lt;span class="nt"&gt;-m&lt;/span&gt; pytest &lt;span class="nt"&gt;-q&lt;/span&gt;

git add proj/envutil.py tests/oracle_empty_proxy.py scripts/bisect-repro.sh
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"fix: treat empty HTTP_PROXY as unset in child env

Regression introduced in &amp;lt;bisect-sha&amp;gt;.
Oracle: tests/oracle_empty_proxy.py
Replay: bash scripts/bisect-repro.sh"&lt;/span&gt;

&lt;span class="c"&gt;# Optional: compare two drafts without losing the pin.&lt;/span&gt;
git range-diff main fix/empty-http-proxy-v1 fix/empty-http-proxy-v2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The commit message is part of the artifact, because maintainers should not reconstruct the bisect from a chat export. Citing the SHA, the oracle path, and the replay command is enough for a reviewer who never saw the original thread. A second draft that drops that citation is a weaker patch even if the diffstat looks smaller. Range-diff is then used to recover the pin rather than to debate formatting.&lt;/p&gt;

&lt;h2&gt;
  
  
  A scoped review packet, not a whole-tree dump
&lt;/h2&gt;

&lt;p&gt;After the pin, a coding model is useful as a second reader, not as an archaeologist for the whole repository. The packet should contain the blamed commit, the oracle, the proposed diff, and the documented contract. It should not contain secrets, &lt;code&gt;.env&lt;/code&gt; files, private traces, or unrelated application code. If any of those files are required to reproduce, the review stays on a private runner.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;p&gt;MonkeyCode's free model access is enough for this step when the packet stays small and the three checks below are explicit. The operator-supplied free server option is relevant when a laptop cannot install the project's native extras, because bisect must run against a clean clone rather than a dirty local venv. The model is asked only whether the diff restores the oracle, whether it widens public surface, and whether the commit message cites the bisect SHA.&lt;/p&gt;

&lt;p&gt;A review prompt that stays inside that scope looks like the following template. It is not a recorded production session, and it is allowed to answer that evidence is missing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are reviewing an OSS regression patch. Do not propose a rewrite.

Inputs:
1) git show --stat &amp;lt;bisect-sha&amp;gt;
2) git show &amp;lt;bisect-sha&amp;gt; -- proj/envutil.py
3) tests/oracle_empty_proxy.py
4) git diff main...HEAD

Checks:
- Does the diff make the oracle pass for empty and missing HTTP_PROXY?
- Does the diff change any function that the blamed commit did not touch?
- Does the commit message cite the bisect SHA and the replay script?
- List any remaining public-API risk in one short bullet list.

If evidence is missing, say "insufficient evidence" instead of guessing.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last instruction is the reason bisect happens before review, because models fill gaps with plausible architecture. Maintainers then spend the review cycle undoing those invented helpers and restored “simplifications.” A packet that may answer “insufficient evidence” is cheaper than a confident patch against the wrong layer. The bisect log remains the source of truth if the model and the contributor disagree.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;This workflow assumes a deterministic oracle and annotated tags that can serve as a control group. Projects that never tag releases cannot form that group without an agreed good SHA written into the issue. Flaky suites poison &lt;code&gt;git bisect run&lt;/code&gt;, because a random red on a good commit sends the search the wrong way. Native extensions, network fixtures, and GPU tests often need &lt;code&gt;125&lt;/code&gt; skips, and those skips can leave a wide blame range instead of a single commit.&lt;/p&gt;

&lt;p&gt;Remote review has a second constraint that no free-tier workspace removes for the contributor. Embargoed security issues, private customer traces, and credentials in fixtures should not leave the maintainer's machine. The bisect script also does not replace project CI; it only names the first bad commit before CI is asked to judge a patch. Generated code and lockfile bumps still need their own toolchain, not a model-authored edit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should not use this approach
&lt;/h2&gt;

&lt;p&gt;First-time contributors who have not yet run the project's test extra should not start with a model review of a guessed diff. Feature requests that add behavior, rather than restore a tagged contract, need a design thread instead of a bisect log. Documentation-only changes and typo fixes do not benefit from this ceremony and will annoy maintainers if the PR is padded with scripts. Teams under a disclosure embargo should keep both the oracle and the patch on private runners.&lt;/p&gt;

&lt;p&gt;The durable output is a replayable script, an oracle that fails for one reason, and a commit that cites the first bad SHA. Maintainers can ignore the model entirely and still trust the pin on a clean checkout. Contributors who already reproduce locally can attach &lt;code&gt;bisect.log&lt;/code&gt; and the replay command so the next reviewer does not repeat the search.&lt;/p&gt;

</description>
      <category>git</category>
      <category>opensource</category>
      <category>testing</category>
      <category>ai</category>
    </item>
    <item>
      <title>The Review Cited a Helper That Never Shipped: Assumption Audits Before an OSS Patch</title>
      <dc:creator>Blake Yang</dc:creator>
      <pubDate>Wed, 09 Sep 2026 15:38:35 +0000</pubDate>
      <link>https://dev.to/datars_7274/the-review-cited-a-helper-that-never-shipped-assumption-audits-before-an-oss-patch-1ooo</link>
      <guid>https://dev.to/datars_7274/the-review-cited-a-helper-that-never-shipped-assumption-audits-before-an-oss-patch-1ooo</guid>
      <description>&lt;p&gt;A mid-size Python library merged a cache around its parser after a polite, confident review. Continuous integration stayed green because the new helper lived only inside the incoming diff. Two days later a maintainer bisected a production traceback and found the praised name only in review notes. The model had recommended &lt;code&gt;load_cached_grammar()&lt;/code&gt;, a function that never existed on &lt;code&gt;main&lt;/code&gt;, and the contributor had implemented the suggestion. Tests asserted against the invented helper, public docs never mentioned it, and callers had no honest way to discover the private surface.&lt;/p&gt;

&lt;p&gt;That failure is common when a model reviews an open-source patch against a vague issue title. Plausible names, error codes, and fixtures appear in the comment thread even though &lt;code&gt;git grep&lt;/code&gt; cannot find them. The workflow below treats invented symbols as a merge blocker. It reproduces the bug, drafts a minimal patch, and then audits every review claim against the tree before anyone clicks merge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why invented helpers survive CI
&lt;/h2&gt;

&lt;p&gt;Green CI does not prove that a review comment described the real codebase. A test imported from the patch can exercise a helper that the patch itself just created. Maintainers reading the model output often treat fluent advice as local knowledge. The result is a private API that no release tag, changelog, or type stub can explain.&lt;/p&gt;

&lt;p&gt;Open-source patches also travel with incomplete context. The model may see a hunk, a stack trace, and a one-line issue title. It rarely sees neighboring modules, historical names, or the public export list. Filling those gaps with confident guesses is the default behavior, not a rare hallucination.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pin the tree before any model reads the diff
&lt;/h2&gt;

&lt;p&gt;Start from a clone at the issue’s reported revision, not from an already edited working tree. Record the remote, the default branch, and the exact commit that still fails. The commands below are a worked example against a fictional parser library named &lt;code&gt;tokparse&lt;/code&gt;; treat paths as placeholders, not as a published project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://example.com/oss/tokparse.git
&lt;span class="nb"&gt;cd &lt;/span&gt;tokparse
git fetch origin
git switch &lt;span class="nt"&gt;--detach&lt;/span&gt; origin/main
git rev-parse HEAD &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/repro.sha
git status &lt;span class="nt"&gt;--porcelain&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the report names a release tag, check that tag out instead of &lt;code&gt;main&lt;/code&gt;. Mixed trees hide whether a failure belongs to the bug or to local edits. Keep secrets, tokens, and untracked editor files out of the worktree so later review prompts cannot leak them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reproduce, then freeze the failing command
&lt;/h2&gt;

&lt;p&gt;Write the smallest command that fails on the pinned commit and save it as a script. Do not let a model invent a test runner, extra pytest flags, or a Docker image that the repository does not already document. Read &lt;code&gt;CONTRIBUTING&lt;/code&gt;, &lt;code&gt;tox.ini&lt;/code&gt;, &lt;code&gt;pyproject.toml&lt;/code&gt;, and &lt;code&gt;.github/workflows&lt;/code&gt; first.&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="c"&gt;# example: documented in the repo's CONTRIBUTING.md&lt;/span&gt;
python &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv
&lt;span class="nb"&gt;.&lt;/span&gt; .venv/bin/activate
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;".[dev]"&lt;/span&gt;
pytest tests/test_parser.py::test_trailing_comma &lt;span class="nt"&gt;-q&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/repro.exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If that test does not exist yet, add one failing assertion that uses only public APIs already imported by neighboring tests. Label the new test as a proposal until it fails for the reported reason. A passing characterization of the wrong behavior is useful; a passing test of an invented helper is not.&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="c1"&gt;# proposal: tests/test_parser.py
# Uses only Parser and ParseError, both imported by existing tests.
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;tokparse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ParseError&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_trailing_comma_is_a_parse_error&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;: 1,}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;ParseError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;trailing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;AssertionError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;expected ParseError for a trailing comma&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;p&gt;Run the test twice on the pinned commit. If the result flips, stop and isolate fixtures before any review model sees the tree. Flaky reproduction turns invented helpers into noise that nobody can falsify.&lt;/p&gt;

&lt;h2&gt;
  
  
  Draft the smallest patch that makes the frozen command pass
&lt;/h2&gt;

&lt;p&gt;Edit only the module that already owns the failing path. Avoid drive-by renames, formatter-only hunks, and new files whose names the issue never required. After the frozen command passes, produce a unified diff against the recorded SHA.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add tests/test_parser.py src/tokparse/parser.py
git diff &lt;span class="nt"&gt;--cached&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/oss.patch
git diff &lt;span class="nt"&gt;--cached&lt;/span&gt; &lt;span class="nt"&gt;--stat&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep the patch nearby as a file, not only as a chat attachment. File-backed diffs can be grepped, hashed, and reapplied. Chat-backed diffs silently pick up extra prose that later looks like source.&lt;/p&gt;

&lt;h2&gt;
  
  
  Artifact: an assumption log plus a symbol gate
&lt;/h2&gt;

&lt;p&gt;The original artifact in this article is a two-file gate. The first file is a human-edited assumption log. The second is a small checker that extracts added names from the patch and rejects review comments that cite missing symbols.&lt;/p&gt;

&lt;h3&gt;
  
  
  Assumption log template
&lt;/h3&gt;

&lt;p&gt;Copy the block below into &lt;code&gt;assumption-log.md&lt;/code&gt; beside the patch. Fill every row before a model is allowed to comment. Mark unknown items as unknown instead of guessing a library convention.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Assumption log for /tmp/oss.patch&lt;/span&gt;
&lt;span class="gh"&gt;# Pinned SHA: (paste from /tmp/repro.sha)&lt;/span&gt;

| ID | Claim | Evidence command | Status |
| --- | --- | --- | --- |
| A1 | Public parser API is &lt;span class="sb"&gt;`Parser.parse`&lt;/span&gt; | git grep -n "class Parser" src | verified |
| A2 | Trailing commas raise &lt;span class="sb"&gt;`ParseError`&lt;/span&gt; | git grep -n "class ParseError" src | verified |
| A3 | No cache helper exists on main | git grep -n "load_cached_grammar" . | absent |
| A4 | Tests run under pytest from tox.ini | sed -n "1,80p" tox.ini | verified |
| A5 | Issue asks for a public cache | unknown; issue body never says cache | blocked |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Status values are only &lt;code&gt;verified&lt;/code&gt;, &lt;code&gt;absent&lt;/code&gt;, or &lt;code&gt;blocked&lt;/code&gt;. &lt;code&gt;blocked&lt;/code&gt; means the patch must not add the claimed behavior. Models are not asked to resolve blocked rows; humans are.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extract names the patch itself introduces
&lt;/h3&gt;

&lt;p&gt;The checker below is a proposal script. It reads a unified diff and prints added identifiers so a later review cannot treat them as pre-existing APIs.&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="c1"&gt;# proposal: tools/extract_added_symbols.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="n"&gt;IDENT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\b([A-Za-z_][A-Za-z0-9_]{2,})\b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;KEYWORDS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;def&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;class&lt;/span&gt;&lt;span class="sh"&gt;"&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&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;import&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;from&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;self&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;None&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;True&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;False&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;as&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;try&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;except&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;raise&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;added_lines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff_text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;diff_text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splitlines&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;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+++&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;---&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+++&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;added_lines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;IDENT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&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;match&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;KEYWORDS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;unique&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&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;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&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 shell"&gt;&lt;code&gt;python tools/extract_added_symbols.py /tmp/oss.patch &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/added.syms
&lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; /tmp/added.syms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verify every review claim with git grep
&lt;/h3&gt;

&lt;p&gt;After a model (or a human) writes review comments, save them as plain text. Then run each cited identifier against the tree at the pinned SHA, not against the index that already contains the patch, unless the comment explicitly talks about new code.&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="c"&gt;# proposal: tools/verify_review.sh&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail
&lt;span class="nv"&gt;SHA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /tmp/repro.sha&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;COMMENTS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="p"&gt;/tmp/review.comments&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Extract backtick-quoted names from review prose.&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-oE&lt;/span&gt; &lt;span class="s1"&gt;'`[A-Za-z_][A-Za-z0-9_]+`'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$COMMENTS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'`'&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/cited.syms

&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; name&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;continue
  &lt;/span&gt;&lt;span class="nv"&gt;hits&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SHA&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; src tests &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="nv"&gt;added&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-Fx&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; /tmp/added.syms &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$hits&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$added&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"INVENTED: &lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$hits&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$added&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"NEW_IN_PATCH: &lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;else
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"PRESENT: &lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;fi
done&lt;/span&gt; &amp;lt; /tmp/cited.syms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any &lt;code&gt;INVENTED&lt;/code&gt; line is a failed gate. Delete that review comment, or rewrite it until &lt;code&gt;git grep&lt;/code&gt; can show a file and a line. &lt;code&gt;NEW_IN_PATCH&lt;/code&gt; lines are allowed only when the assumption log already accepted that new name.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision table for keeping a review comment
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Review comment type&lt;/th&gt;
&lt;th&gt;Evidence required&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mentions a function, class, or constant&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;git grep&lt;/code&gt; hit on the pinned SHA, or a &lt;code&gt;NEW_IN_PATCH&lt;/code&gt; row already accepted&lt;/td&gt;
&lt;td&gt;keep or rewrite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mentions a test file or fixture&lt;/td&gt;
&lt;td&gt;path exists in &lt;code&gt;git ls-tree -r --name-only $SHA&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;keep or rewrite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Asks for a new helper not in the issue&lt;/td&gt;
&lt;td&gt;assumption log row is &lt;code&gt;blocked&lt;/code&gt; or &lt;code&gt;absent&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;discard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Style-only advice that rewrites unrelated hunks&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;git diff --stat&lt;/code&gt; would grow beyond the failing module&lt;/td&gt;
&lt;td&gt;discard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claims CI already covers a branch&lt;/td&gt;
&lt;td&gt;job name appears in &lt;code&gt;.github/workflows&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;keep only with a file citation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security or secret-handling advice&lt;/td&gt;
&lt;td&gt;human maintainer review; do not run extra scanners on a shared machine&lt;/td&gt;
&lt;td&gt;escalate, do not auto-apply&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The table is the review policy. Models do not get a vote on discarded rows. Humans may still apply a discarded idea later, but only after a new assumption row is verified.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where a free model actually helps
&lt;/h2&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach. After the assumption log and symbol files exist, a free model can review &lt;code&gt;/tmp/oss.patch&lt;/code&gt; against those files instead of against an empty prompt. MonkeyCode’s free model access and free server option are relevant here only as a place to run that constrained pass and to execute &lt;code&gt;pytest&lt;/code&gt; plus &lt;code&gt;verify_review.sh&lt;/code&gt; on a clean checkout. The model prompt should attach the patch, the assumption log, the added-symbol list, and a hard rule: cite a path or mark the comment as speculation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are reviewing an OSS patch. You may cite identifiers only if they
appear in assumption-log.md, added.syms, or the attached diff.
If you need a helper that is not listed, write SPECULATION and stop.
Do not invent test runner flags. Do not invent CI job names.
Return comments as: path:line: severity: text.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server side of the loop is just a clean clone, the frozen test command, and the grep gate. It is not a substitute for the project’s own CI. If the repository contains credentials, private submodules, or production data dumps, skip shared machines and run the same scripts locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;Symbol presence is not semantic correctness. A helper can exist and still be the wrong layer for the bug. Grep also false-positives on comments, dead code, and similarly named tests. Binary files, generated protobufs, and vendored trees need a different inventory than the script above. The workflow does not prove license, CLA, or maintainer-tone issues. It only blocks a frequent class of fluent, wrong review comments.&lt;/p&gt;

&lt;p&gt;The loop also costs a checkout and a full test run before any model token is spent. Tiny typo patches do not repay that cost. Neither do issues that already include a failing test, a one-line fix, and a maintainer who asked only for a rebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should not use this approach
&lt;/h2&gt;

&lt;p&gt;Skip the assumption audit when the change is a spelling fix in documentation with no code hunks. Skip it when the project forbids AI-assisted review in &lt;code&gt;CONTRIBUTING&lt;/code&gt;. Skip shared free servers when the reproducer needs customer fixtures or secrets. Skip it when the reporter already attached a bisect SHA, a failing test, and a two-line patch that &lt;code&gt;git apply --check&lt;/code&gt; accepts. In those cases a human maintainer is faster than a gated model pass.&lt;/p&gt;

&lt;p&gt;Contributors who already pin a SHA, freeze a failing command, and grep review comments against the tree can run the same constrained pass with MonkeyCode’s free model access on the free server option, then throw away every &lt;code&gt;INVENTED&lt;/code&gt; line before opening the pull request.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>testing</category>
      <category>git</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
