<?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: OHCAYGO</title>
    <description>The latest articles on DEV Community by OHCAYGO (@ohcaygo).</description>
    <link>https://dev.to/ohcaygo</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%2F4105022%2Fa41d4801-4c42-45fb-856d-7cb461402cdf.png</url>
      <title>DEV Community: OHCAYGO</title>
      <link>https://dev.to/ohcaygo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ohcaygo"/>
    <language>en</language>
    <item>
      <title>What green CI doesn’t prove after a PR’s base moves</title>
      <dc:creator>OHCAYGO</dc:creator>
      <pubDate>Tue, 01 Sep 2026 21:58:53 +0000</pubDate>
      <link>https://dev.to/ohcaygo/what-green-ci-doesnt-prove-after-a-prs-base-moves-2c29</link>
      <guid>https://dev.to/ohcaygo/what-green-ci-doesnt-prove-after-a-prs-base-moves-2c29</guid>
      <description>&lt;p&gt;A pull request can be conflict-free, have green CI, and still lack evidence that the final merged state was ever checked.&lt;/p&gt;

&lt;p&gt;That is the narrow problem behind &lt;a href="https://github.com/ohcaygo/merge-proof" rel="noopener noreferrer"&gt;merge-proof&lt;/a&gt;, a small open-source Git / GitHub Action tool I just published.&lt;/p&gt;

&lt;p&gt;This is not a claim that AI-authored code is broken. It is not a claim that GitHub CI is broken. It is not a claim that a flagged PR contains a bug.&lt;/p&gt;

&lt;p&gt;It is only about evidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  The strongest objection first
&lt;/h2&gt;

&lt;p&gt;If your repository uses strict required status checks correctly, and especially if it uses a properly configured GitHub merge queue, that is the stronger answer to base drift.&lt;/p&gt;

&lt;p&gt;A merge queue tests the combined state before merge. For the specific problem of "did this PR get validated against the base it is actually merging into?", that is better than a diagnostic tool after the fact.&lt;/p&gt;

&lt;p&gt;merge-proof is narrower. It is useful where that stronger enforcement is absent, incomplete, advisory, or not easy to inspect. It surfaces the evidence gap: which base commit, which candidate commit, which overlapping files, and which protected-path categories made the result unproven.&lt;/p&gt;

&lt;p&gt;If your conclusion is "GitHub already solves the valuable part of this for my repo," that is useful feedback, and I would rather hear it than not.&lt;/p&gt;

&lt;h2&gt;
  
  
  The merge-state evidence problem
&lt;/h2&gt;

&lt;p&gt;A common PR path looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A branch is cut from &lt;code&gt;main&lt;/code&gt; at commit A.&lt;/li&gt;
&lt;li&gt;CI runs on the candidate branch and passes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;main&lt;/code&gt; moves to commit B while the PR is open.&lt;/li&gt;
&lt;li&gt;The PR still merges cleanly.&lt;/li&gt;
&lt;li&gt;The final merged state is now B plus the PR.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The clean merge only tells you Git could combine the text. It does not prove that CI, review, or any other validation checked that exact combination.&lt;/p&gt;

&lt;p&gt;This matters most when the base changed in files the PR also changed. There may be no conflict, but the combined behavior was not the state represented by the earlier green check.&lt;/p&gt;

&lt;h2&gt;
  
  
  What merge-proof checks today
&lt;/h2&gt;

&lt;p&gt;merge-proof currently implements two blocking checks.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;BASE_DRIFT_UNVERIFIED&lt;/code&gt; — the base advanced after the candidate diverged, and files changed by the candidate were also changed on the base during that interval.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;PROTECTED_BOUNDARY&lt;/code&gt; — the candidate changes paths classified as expensive to undo if merged without explicit evidence: migrations, schemas, auth, secrets, billing, or access-policy / RLS / RBAC areas.&lt;/p&gt;

&lt;p&gt;It also reports &lt;code&gt;STALE_BASE&lt;/code&gt; as advisory only, and reports CI and deployment configuration changes as an advisory &lt;code&gt;ci-deploy&lt;/code&gt; category. Neither advisory changes the verdict.&lt;/p&gt;

&lt;p&gt;The tool runs on local Git state. It has zero npm dependencies. It makes no network calls, no model calls, no API calls, and has no telemetry. In shallow clones it fails closed instead of reporting confidence from history it could not see.&lt;/p&gt;

&lt;p&gt;One disclosure: the GitHub Action wrapper's only third-party dependency is &lt;code&gt;actions/github-script@v7&lt;/code&gt;, a GitHub-owned action, used solely to post the optional sticky PR comment. The verifier itself has none.&lt;/p&gt;

&lt;h2&gt;
  
  
  What merge-proof does not check
&lt;/h2&gt;

&lt;p&gt;This release does not read CI results, so it cannot establish &lt;code&gt;CI_RAN_ON_FINAL_HEAD&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It does not read reviews or approvals.&lt;/p&gt;

&lt;p&gt;It does not verify that a candidate is durable on a remote.&lt;/p&gt;

&lt;p&gt;It does not compare a PR against a declared scope.&lt;/p&gt;

&lt;p&gt;It is not a bug detector, security scanner, code reviewer, human-approval verifier, or correctness proof. A &lt;code&gt;VERIFIED&lt;/code&gt; result only means the implemented checks did not find their specific evidence gaps.&lt;/p&gt;

&lt;h2&gt;
  
  
  The study
&lt;/h2&gt;

&lt;p&gt;We ran merge-proof against 2,037 agent-authored PRs across 32 public repositories. 24.1% returned &lt;code&gt;NOT_PROVEN&lt;/code&gt; under the implemented checks.&lt;/p&gt;

&lt;p&gt;Immediately important: &lt;code&gt;NOT_PROVEN&lt;/code&gt; does not mean broken or buggy. It means the repository does not contain evidence that the candidate was validated against the state it merged into. No conclusion about code correctness follows from that verdict. This is a prompt to look, not an accusation.&lt;/p&gt;

&lt;p&gt;The exact result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2,037 usable PRs&lt;/li&gt;
&lt;li&gt;42 unresolvable PRs excluded from all rates&lt;/li&gt;
&lt;li&gt;490 &lt;code&gt;NOT_PROVEN&lt;/code&gt;, or 24.1%&lt;/li&gt;
&lt;li&gt;1,547 &lt;code&gt;VERIFIED&lt;/code&gt;, or 75.9%&lt;/li&gt;
&lt;li&gt;0 &lt;code&gt;FAIL&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;410 base-drift findings, or 20.1%&lt;/li&gt;
&lt;li&gt;109 protected-path findings, or 5.4%&lt;/li&gt;
&lt;li&gt;29 PRs triggered both conditions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The study used deterministic Git data. Agent-authored PRs were identified from commit trailers, not model judgment. The scan walked squash merges on the default branch's first-parent history, used the squash commit's first parent as the base-at-merge, fetched the PR head directly, and ran the same analyzer that ships in the package — not a separate research implementation.&lt;/p&gt;

&lt;p&gt;It is reproducible from the repository:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
bash
node study/collect.js --repos study/repos.txt --out study-data.json --max-prs 80 --prune true
node study/summarize.js study-data.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>github</category>
      <category>devops</category>
      <category>testing</category>
      <category>ci</category>
    </item>
  </channel>
</rss>
