<?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: Tufan Tunç</title>
    <description>The latest articles on DEV Community by Tufan Tunç (@tufan_tunc).</description>
    <link>https://dev.to/tufan_tunc</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%2F4073250%2F55bdf32b-cdf1-4c6b-bccb-04750b76ace8.jpg</url>
      <title>DEV Community: Tufan Tunç</title>
      <link>https://dev.to/tufan_tunc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tufan_tunc"/>
    <language>en</language>
    <item>
      <title>The agent didn't hallucinate. It ignored what the repo already knew.</title>
      <dc:creator>Tufan Tunç</dc:creator>
      <pubDate>Tue, 11 Aug 2026 14:15:40 +0000</pubDate>
      <link>https://dev.to/tufan_tunc/the-agent-didnt-hallucinate-it-ignored-what-the-repo-already-knew-2m44</link>
      <guid>https://dev.to/tufan_tunc/the-agent-didnt-hallucinate-it-ignored-what-the-repo-already-knew-2m44</guid>
      <description>&lt;p&gt;&lt;em&gt;I pre-registered a small study, pointed a 12-reviewer pipeline at three merged Copilot PRs in major .NET organisations, and the failure mode I found was not the one everyone talks about.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Disclosure first:&lt;/strong&gt; I maintain &lt;a href="https://github.com/tufantunc/review-pro" rel="noopener noreferrer"&gt;review-pro&lt;/a&gt;, the open-source review system used as the instrument here. This article exists because I wanted to know whether its premise survives contact with real data. Part of it didn't. That's in here too, along with the two findings I got wrong myself and the tool caught.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;You have an agent write a feature. You ask an agent to review it. What comes back is unhelpful in one of two directions: forty nitpicks, or a cheerful approval.&lt;/p&gt;

&lt;p&gt;The usual explanation for why AI-written code needs its own review discipline is &lt;em&gt;hallucination&lt;/em&gt; — invented APIs, imports that don't exist, config keys nobody defined. My tool ships a reviewer dedicated to exactly that, so I had every incentive to find it.&lt;/p&gt;

&lt;p&gt;I went looking for it in the most honest place I could think of: &lt;strong&gt;agent-authored pull requests that real maintainers already merged into serious codebases.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The method, in brief
&lt;/h2&gt;

&lt;p&gt;Before running anything, I wrote down what would count — a pre-registration with the corpus criteria, the classification buckets, and anti-gaming rules (first run counts, no diff dropped after seeing its findings, false-positive rate published whatever it is, negative results published). The full document and per-case records are public; nothing below was decided after seeing results, and the two things that were are marked as dated amendments in it.&lt;/p&gt;

&lt;p&gt;The instrument: &lt;strong&gt;review-pro doesn't ask one LLM to review the diff.&lt;/strong&gt; A triage pass reads the change and dispatches only the relevant specialist reviewers — each with a single mandate and its own scoped context — then a synthesis pass dedups overlapping findings, resolves conflicts by domain ownership, and emits one verdict. The rule that matters most for this study: reviewers are required to &lt;strong&gt;locate evidence in the repository before making a claim&lt;/strong&gt;; an unverified "this looks wrong" is forbidden by their rubric.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;diff
 └── triage — which reviewers does this change actually need?
      ├── correctness     ┐
      ├── api-contract    │  only the relevant specialists,
      ├── tests           │  in parallel — each must locate
      ├── craft           │  repo evidence for every claim
      └── ai-antipatterns ┘  (12 exist; the chore diff got 4)
           └── synthesis — dedup, resolve conflicts, one verdict
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the shape under test, not just the tool: whether specialised, evidence-required review finds what a single diff-reading pass cannot.&lt;/p&gt;

&lt;p&gt;The corpus: merged PRs authored by GitHub's Copilot coding agent (&lt;code&gt;author:app/copilot-swe-agent&lt;/code&gt; — GitHub itself attributes them, no vibes-based "this looks AI-written"), in established organisations, 30–400 changed lines, taken by recency rather than by browsing for juicy diffs. Three cases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A .NET versioning library&lt;/strong&gt; — 71 lines adding &lt;code&gt;HEAD~2&lt;/code&gt;-style ancestor parsing to the core lookup path. Merged with &lt;strong&gt;zero review comments&lt;/strong&gt; and an empty approval, 12/12 CI green.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A widely-used AI extensions library&lt;/strong&gt; — 125 lines deleting a raw-JSON workaround for an upstream SDK bug, plus a dependency bump. Merged with &lt;strong&gt;two human approvals&lt;/strong&gt; and inline discussion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;E2E test infrastructure in a large app framework&lt;/strong&gt; — 48 lines of timeout hardening. A chore, included deliberately as a noise-floor test.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I anonymise the repos in this article because the argument is about a pattern, not about naming maintainers who merged something. The full records — PR links included — are &lt;a href="https://github.com/tufantunc/review-pro/tree/main/studies/2026-08-copilot-pr-pilot" rel="noopener noreferrer"&gt;published with the pre-registration&lt;/a&gt;, since "verified by hand" is only worth something if you can check it; the article body keeps them unnamed so the piece stays about the pattern, not the people.&lt;/p&gt;

&lt;p&gt;One observation before any review ran, recorded in the pre-registration because it cuts against my own thesis: &lt;strong&gt;merged agent PRs in serious orgs skew heavily mechanical.&lt;/strong&gt; Version bumps, lint fixes, dependency updates, a disabled flaky test. If most agent code that actually ships is mechanical, the surface for "confidently invented an API" is narrower than the discourse assumes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Result 1: in this corpus, the falsifiable categories fired once — never for hallucination itself
&lt;/h2&gt;

&lt;p&gt;My tool's AI-antipatterns reviewer has three &lt;em&gt;falsifiable&lt;/em&gt; categories — claims that are objectively true or false, where I could verify every finding by hand:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Case 1&lt;/th&gt;
&lt;th&gt;Case 2&lt;/th&gt;
&lt;th&gt;Case 3&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hallucinated API / symbol / import&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Invented config / env key&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Needless dependency&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every symbol, import, and config key these agents wrote &lt;strong&gt;existed&lt;/strong&gt;. I checked by hand; the reviewer checked independently; we agreed. The one hit was a dependency bump whose stated rationale didn't hold up — more on that below, because it's the most interesting defect of the lot.&lt;/p&gt;

&lt;p&gt;If you came here for "LLMs make up functions," this is a negative result, and I'm publishing it as one. In this corpus, merged agent code simply doesn't look like that. Tool access — agents grepping before they import — may well be part of why, but that's a hypothesis about mechanism, and this study didn't test it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Result 2: what fired instead
&lt;/h2&gt;

&lt;p&gt;The category that fired repeatedly — and produced every finding that would have changed a merge decision — was &lt;strong&gt;ignored convention&lt;/strong&gt;. Not inventing things the codebase doesn't have. Failing to notice things it does.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 1.&lt;/strong&gt; The new ancestor-walking code calls a throwing API inside a method whose documented contract is "return null when not found." That alone is an ordinary bug. What makes it interesting: the repository &lt;em&gt;already knows about this exact failure mode&lt;/em&gt;. There is a canonical guard elsewhere, with a comment that says, verbatim, &lt;em&gt;"Our managed git implementation throws this on shallow clones."&lt;/em&gt; The agent's code sits outside that guard, so &lt;code&gt;get-version HEAD~1&lt;/code&gt; in a shallow CI clone regresses from a clean "bad ref" exit code to a raw internal error. Same story twice over: the repo knows how to peel annotated tags — there's a helper that does it — and the new code doesn't, so &lt;code&gt;&amp;lt;release-tag&amp;gt;~1&lt;/code&gt; cannot resolve at all. In a &lt;em&gt;tag-driven versioning tool&lt;/em&gt;, where the ancestor of a release tag is arguably the headline use case.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 2.&lt;/strong&gt; The PR deletes ~97 lines of defensive raw-JSON parsing, citing an upstream SDK bug as fixed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What the PR assumed&lt;/strong&gt; — the SDK bug is fixed; the workaround can go.&lt;br&gt;
&lt;strong&gt;What the upstream source shows&lt;/strong&gt; — the fix covers exactly one of the two fields the workaround defended.&lt;br&gt;
&lt;strong&gt;What that means on the wire&lt;/strong&gt; — &lt;code&gt;"created_at": null&lt;/code&gt; still throws the exact exception class the PR claims is gone.&lt;br&gt;
&lt;strong&gt;The review consequence&lt;/strong&gt; — adopting the typed API was fine; retiring the &lt;em&gt;whole&lt;/em&gt; guard on the strength of a one-field fix was not.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I verified the middle two lines from the SDK's generated deserializer at both version tags:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// "bytes" — null guard present in BOTH the old and new SDK version&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NameEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bytes"&lt;/span&gt;&lt;span class="n"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ValueKind&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;JsonValueKind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;sizeInBytes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// "created_at" — no guard in either version, non-nullable target&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NameEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"created_at"&lt;/span&gt;&lt;span class="n"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;createdAt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTimeOffset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromUnixTimeSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetInt64&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the falsifiable-category hit: the version bump justifying all this was unnecessary for its stated purpose. The fix was &lt;strong&gt;already present in the version the repo was on&lt;/strong&gt;. The bump is only needed because the agent rewrote one call to the newer version's API shape — a self-inflicted dependency change on a shipped package, framed as a bug-fix requirement. Two human reviewers approved it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 3.&lt;/strong&gt; Even the chore had a version of this. The new timeout constant's doc comment says it "mirrors the explicit budget an existing helper already sets." It inverts it — the existing helper derives the budget &lt;em&gt;from&lt;/em&gt; the wait; the new code derives the wait from the budget. And the constant got applied to two call sites that launch via &lt;code&gt;dotnet run&lt;/code&gt;, where the environment variable it's calibrated against is never set, turning a documented invariant into dead prose and a 2-minute failure into a 4-minute one.&lt;/p&gt;

&lt;p&gt;Here's the pattern in one sentence: &lt;strong&gt;the defects were not in what the agent wrote, but in what the agent didn't know the codebase already knew.&lt;/strong&gt; The evidence for every one of these lives in files the diff never touched — a guard in another module, an upstream deserializer, a sibling helper's coupling direction. Which is precisely why a human skimming the diff, or an agent reviewing only the diff, won't catch them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Result 3: green CI certified none of the things that mattered
&lt;/h2&gt;

&lt;p&gt;Case 2's test suite is &lt;em&gt;good&lt;/em&gt; — 900+ lines driving the real SDK through a fake HTTP handler. It still could not test the PR's central premise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not one fixture in the project sends an explicit &lt;code&gt;"bytes": null&lt;/code&gt;. They all &lt;em&gt;omit&lt;/em&gt; the field — a different deserializer path. The suite passes identically whether the upstream bug is fixed or not.&lt;/li&gt;
&lt;li&gt;The only &lt;code&gt;has_more&lt;/code&gt; value in the project is &lt;code&gt;false&lt;/code&gt;. The pagination rewrite — replacing careful manual paging with SDK auto-pagination — has zero multi-page coverage. The upstream bug was reported as crashing &lt;em&gt;during auto-pagination&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Twelve green checks on case 1. Green CI everywhere. In no case did CI exercise the actual risk the change carried. "Tests pass" and "someone traced the shallow-clone path" are different claims, and only one of them is cheap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Result 4: the tool corrected me. Twice.
&lt;/h2&gt;

&lt;p&gt;I wrote my own ground-truth notes before each dispatch, so I could score the tool against an independent read. Embarrassingly, the scoring went both ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I flagged &lt;code&gt;HEAD~2000000000&lt;/code&gt; as an unbounded loop. Two reviewers independently traced that the loop exits at the root commit — bounded by history depth, not by user input — and both cited the PR's own &lt;code&gt;HEAD~999&lt;/code&gt; test as proof. I was wrong.&lt;/li&gt;
&lt;li&gt;I flagged a hard-coded env-var name where the repo "has a canonical constant." Three reviewers established the constant is &lt;code&gt;internal&lt;/code&gt;, in an assembly the test project doesn't reference, with &lt;code&gt;InternalsVisibleTo&lt;/code&gt; granted to two other projects only — and that the literal is the file's pre-existing idiom. Wrong again.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both of my false positives were exactly the genre of confident-but-unverified claim this whole article is about. The discipline that caught them wasn't mine; it was a rule in the reviewers' rubric: &lt;em&gt;no finding without located, verified evidence.&lt;/em&gt; If you take one implementation idea from this piece, take that one.&lt;/p&gt;

&lt;p&gt;The traffic also flowed the other way: a reviewer read the PR's &lt;em&gt;commit history&lt;/em&gt; (I had only read the diff) and found that the PR's own final commit was a build-break fix necessitated by its hand-rolled index arithmetic — evidence for a simpler implementation, sitting in the PR itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  What didn't work
&lt;/h2&gt;

&lt;p&gt;Honesty section. Three things, all going in my issue tracker:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One finding was right for a wrong reason.&lt;/strong&gt; A reviewer correctly flagged missing multi-page test coverage, but claimed the test harness needed rework to support it. False — the harness already takes a request-predicate function, and other tests use it. A reader acting on that remedy does an unnecessary refactor. Core claim true, supporting claim wrong; I'm counting these separately from clean true positives.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leaving the repo is not automatic.&lt;/strong&gt; Two reviewers correctly flagged the case-2 premise as "unverified by the repo" — but didn't go check the upstream SDK themselves. The two that did (and nailed it) included one I had explicitly told to. Repo-grounded verification is reliable; external fact-checking currently depends on the mandate you give the reviewer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;n = 3.&lt;/strong&gt; This is a pattern I observed under pre-registered rules, not a proven population claim. I'd genuinely like to see someone run the same protocol on Rust or TypeScript corpora and publish disagreement.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why twelve reviewers and not one
&lt;/h2&gt;

&lt;p&gt;The shape was sketched in the method section; here's why the data justifies it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The strongest case-1 finding was independently produced by &lt;strong&gt;four&lt;/strong&gt; reviewers from four different angles (contract, error path, maintainability, convention) and collapsed into one item by a synthesis pass. That convergence is signal you can't get from one context.&lt;/li&gt;
&lt;li&gt;Reviewers &lt;em&gt;disagreed&lt;/em&gt; — one flagged a partial rollout, another scoped the same observation out as pre-existing. Both defensible; synthesis resolves it by domain ownership. A single agent would never even surface the tension.&lt;/li&gt;
&lt;li&gt;Silence stayed cheap. On the chore diff, triage dispatched 4 reviewers instead of 7, one returned zero findings, and another explicitly declined five would-be findings with reasons. Noise is the failure mode everyone predicts for fan-out review; the noise floor is what I most wanted to measure, and it held.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;The distribution of agent-code failure has shifted somewhere the discourse hasn't followed. In this corpus, at least, it wasn't invention. It was &lt;strong&gt;locally plausible code written with no memory of the codebase's accumulated knowledge&lt;/strong&gt;: the guard someone added after a production incident, the peel helper, the coupling direction a sibling function established. Every one of those is invisible in the diff and discoverable only by tracing what the diff touches.&lt;/p&gt;

&lt;p&gt;That's a reviewable property. But it means review has to &lt;em&gt;leave the diff&lt;/em&gt; — search the repo, read the callers, check the upstream source — and it means "reviewed" has to mean more than an approval on green CI. The diff is where the change is. The repository is where the evidence is.&lt;/p&gt;

&lt;p&gt;If you want to poke at this, here's what running it looks like — install once, then invoke the skill on a branch inside your agent tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/plugin marketplace add tufantunc/review-pro     &lt;span class="c"&gt;# Claude Code&lt;/span&gt;
/plugin &lt;span class="nb"&gt;install &lt;/span&gt;review-pro@review-pro
&lt;span class="c"&gt;# then, in a session on the branch under review:&lt;/span&gt;
&lt;span class="s2"&gt;"review this branch with review-pro"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here's what a finding looks like. This one is real — case 1 of the pilot, condensed from the full record:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;High&lt;/span&gt;
  &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api-contract.breaking&lt;/span&gt;
  &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;src/.../ManagedGit/GitRepository.cs&lt;/span&gt;
  &lt;span class="na"&gt;line&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;379&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;new `~` path makes public Lookup throw where its&lt;/span&gt;
         &lt;span class="s"&gt;documented contract is "otherwise &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
  &lt;span class="na"&gt;evidence&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GetCommit (line 329) throws GitException on a missing&lt;/span&gt;
            &lt;span class="s"&gt;object; every pre-existing path in Lookup returns &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;
  &lt;span class="na"&gt;impact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;get-version HEAD~1 in a shallow CI clone regresses from&lt;/span&gt;
          &lt;span class="s"&gt;a clean BadGitRef exit to a raw InternalError&lt;/span&gt;
  &lt;span class="na"&gt;remedy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;resolve the parent via the non-throwing TryGetObjectBySha&lt;/span&gt;
          &lt;span class="s"&gt;before walking, keeping the documented &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="s"&gt; contract&lt;/span&gt;
  &lt;span class="na"&gt;confidence&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;high&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tool is MIT, plain markdown, runs in Claude Code / opencode / Cursor / Codex (&lt;a href="https://github.com/tufantunc/review-pro" rel="noopener noreferrer"&gt;repo&lt;/a&gt;). The most useful thing you can send me is not a star — it's a false positive or a missed finding, with the code. There's an issue template for exactly that; the rubrics get calibrated from real examples, and this article is what that calibration process looks like when you point it at the tool itself.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Pre-registration, amendments, and full per-case findings: &lt;a href="https://github.com/tufantunc/review-pro/tree/main/studies/2026-08-copilot-pr-pilot" rel="noopener noreferrer"&gt;studies/2026-08-copilot-pr-pilot&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>codereview</category>
      <category>opensource</category>
      <category>github</category>
    </item>
  </channel>
</rss>
