method · v4 · this page changes only when the method does

Method

Applies to re audit in this source. Sections 1–4 are the rules this source computes (method v4). Section 5 is what v2 changed, section 6 what v3 added, and section 6b the one rule v4 changed. Published reports stay on the method that produced them. Reports #1 and #2 are method v2. Reports #3 and #4, and any audit produced by the 0.3.0 release, are method v3. Report #4 is 10.5281/zenodo.23196011. This source does not recompute them.

Causari publishes counts about repositories that are not ours. The only honest way to do that is to publish, next to every number, exactly how it was obtained, what it cannot see, and how to reproduce or contest it. This page is that.

1What is counted

For a repository at a given HEAD, re audit walks git log --no-merges and classifies each commit from machine-readable metadata only: the commit message trailers and the author identity. No model, no heuristic on the diff, no guess from style. Merge commits are excluded.

SignalClass
git-ai note under refs/notes/ai that names a non-empty tool in sessions or promptsVERIFIED · that tool
Trailers Drafted-With, Executed-By, AI-Model, AI-Agent, AI-Tool, AI-Assisted: yes and the AI-* family with a positive valueVERIFIED
Co-Authored-By naming a known agent identity (Claude, Copilot, aider, Codex, ChatGPT, OpenHands; Devin, Jules, Gemini and Cursor only with a bot identity or vendor domain)VERIFIED
Author identity of a known agent (aider, noreply@anthropic.com, devin-ai, openhands, cursoragent, google-labs-jules)VERIFIED
Message contains (aider) or Generated with Claude CodePROBABLE
Anything elseUNKNOWN · never counted

VERIFIED and PROBABLE are never summed. Published measurements use VERIFIED only. A note that has only schema_version, only a human declaration, or a tool that is empty or whitespace is not a signal. Detection continues with the other rows. Absence of a qualifying signal is UNKNOWN. UNKNOWN is not human.

2How survival is computed

Introduced = lines added by each classified commit (git log --numstat), text files only, excluding lockfiles, vendored and generated paths. Still at HEAD = for every tracked file, git blame --line-porcelain HEAD; a line counts for the commit blame attributes it to, capped at that commit's introduced count. The ratio is the sum over all classified commits, so it is line-weighted.

The ratio is the persistence of lines that this method associates with its tagged cohort. It does not, by itself, establish code quality, developer productivity, total AI usage, that a model wrote the line, security, correctness, or a causal benefit or harm of AI.

3What it cannot see

4Known ways the number misleads (method v1)

Bulk commits dominate

Because the ratio is line-weighted, one commit that vendors a tree, snapshots documentation or checks in a generated bundle can hold nearly every introduced line of a repository. The published row then measures that commit's fate, not the project's. Example in the current data: one documentation-versioning commit of 3.2 million lines determines a repository's entire ratio. We publish it with the mark "one agent ≥ 90 %" because hiding it would be worse than showing it, and because the fix belongs in the method, not in the table.

re audit owner/repo --json
# largest_commit_share, capped_survival_rate

Formatting and moves count as death

git blame runs without -w, -M, -C: a formatter pass, a re-indent, or moving a function to another file re-attributes those lines.

git blame -w -M -C --line-porcelain HEAD
# what method v2 runs instead

Small samples

Below 5 AI-tagged commits no ratio is published: one commit can dominate. The counts are still printed, with the coverage block saying so.

re audit --json
# "coverage": { "small_sample": true, "sample_floor": 5 }

Age

Survival decays with time since the commit. Early adopters look different from last week's adopters. Method v1 does not normalise for age; compare a repository with itself over time instead.

re audit --save   # append a snapshot to .causari/audits/
# method v3: "baseline": { "by_age": [...], "age_matched": {...} }

A cleared or rewritten repository

When a project empties its tree and starts over, or ports everything in one pass, no line older than that day survives, tagged or not. The AI-tagged ratio then measures the rewrite. Example in the current data: one repository was ported in April 2026 and cleared in July; 6,584 of its commits, 1,529 of them AI-tagged, predate the oldest line still at HEAD; its ratio of 30 % over all AI-tagged lines is 53 % over the lines that postdate that day. Methods v1 and v2 cannot tell; v3 names the oldest surviving line and counts what lies behind it.

re audit --json
# "baseline": { "oldest_surviving": { "date", "commits_before", ... } }

5Method v2

Method v2 caps per-commit weight (a commit weighs at most the 95th percentile of per-commit introduced counts in its repository, never more than 10,000 lines) and reports the capped ratio, the median per-commit ratio and the largest commit's share alongside the line-weighted ratio; runs blame with -w -M -C and honours .git-blame-ignore-revs; parses the trailer block with git's own rules; reads Assisted-by:; refuses shallow clones; and writes a coverage block into every result. The weekly Survival Report adds bootstrap intervals over the sampled repositories. Every published number carries the method version that produced it.

6Method v3: the same repository as the baseline

An AI-tagged ratio on its own answers "how much of this code is still there", not "compared with what". Method v3 answers the second question with the only baseline that shares the repository's conventions, reviewers, formatter passes and rewrites: the untagged lines of the same repository. Every UNKNOWN commit (no machine-readable AI signal: human-written, inline-completed and untagged-agent code alike) enters a baseline block. It costs nothing extra; git log --numstat already walks every commit and git blame already names the owner of every line. PROBABLE commits are in neither cohort.

The gap is a count from one repository's own history, not a verdict on a tool: the untagged cohort includes AI code that carried no tag, and the granularity is still the commit. It is tagged_rate minus untagged_rate, printed in percentage points directly under the survival percentage. Positive means the metadata-matched lines have the higher line-weighted survival in those windows. The windows are age buckets, not identical timestamps. When no age window holds at least 5 commits of both kinds, the audit says the gap is unavailable. It is also in --summary and in the JSON; the Survival Report shows it per repository from the first report built with v3. Three repositories measured while writing this section: −6.0 points (the cleared one above), −4.7 and +5.4, the last with one commit holding 70 % of its AI-tagged lines. Five commits is the comparability floor, not a reliability guarantee.

re audit owner/repo
#   Age-matched gap: -4.7 percentage points (AI-tagged 62.4% minus untagged 67.1% in the matched age windows). Positive means the metadata-matched lines have the higher line-weighted survival in those windows, over 1 matched age window holding …% of the AI-tagged lines. Lines outside those windows are not in this gap.
# Baseline: untagged lines of the same repository
#   line age      AI-tagged            untagged
#   90-180 d      83.2% (33 commits)   96.1% (674 commits)

6bMethod v4: a git-ai note needs a named tool

Method v4 keeps the v3 baseline and every other v3 rule. It changes one classification. Under v3, any parseable git-ai note under refs/notes/ai was VERIFIED, and a note with no tool was recorded as agent ai at confidence 1.0. Under v4 that note is not AI evidence. A non-empty tool in sessions or prompts still is, and it is recorded as that tool. An empty tool does not hide a later named tool, and a note with no qualifying tool does not hide an independent trailer. Named-tool notes stay. The ref is not dropped.

The same frozen repository can therefore change number between v3 and v4. On the corpus of Survival Report #3 the schema-only fallback was two commits in cloudflare/workers-sdk. Removing only those changed the aggregate from 61.3921% to 61.3898% (−0.0023 percentage points). The published median gap did not move, and no repository left the cohort. Report #3 remains the v3 measurement. It is not recomputed. Report #4 (10.5281/zenodo.23196011) is also method v3, produced by the 0.3.0 binary, and is not recomputed.

Commit granularity is unchanged. A qualifying signal still tags the commit, not the line range inside the note.

7Reproduce or contest any number

curl -fsSL https://causari.dev/install.sh | sh
re audit owner/repo --json      # counts, coverage.method, blame flags, repository.head
re audit owner/repo --summary   # the same reading, as Markdown
re audit owner/repo --seal      # those JSON bytes, signed for that commit and method
re seal verify audit.seal.json  # or drop the file on causari.dev/verify

--json and the seal store the counts, repository.head, coverage.method, coverage.blame_flags, and the other coverage flags. They do not store refs/notes/ai. Naming that ref is not the same as keeping its bytes: it is not part of the commit, so adding or removing it can change the class while the stored SHA stays. A repository that has moved has a different commit, and this export does not reproduce the published number. --badge and --card write SVGs. re report reads the local ledger; it does not export an audit. If your reproduction differs, or a row is wrong, open an issue with the JSON. Corrections are made in public and recorded in the data history. Maintainers who do not want their repository measured add one line to .github/survival-optout.txt; the next weekly run drops the row and it is not re-added.

8How repositories are selected

The Survival Report measures the repositories listed in .github/survival-repos.txt: a hand-picked part, added by pull request, and a part filled every week, the day before the report, by scripts/survival_discover.py from the GitHub commit search API. The script looks for public, non-merge commits that carry the same signals section 1 classifies as VERIFIED (the Co-Authored-By identities, the provenance trailers, the agent author identities) and samples the most recent ones per signal. For every repository sampled at least twice it reads the star count first. The repository-wide commit count is requested only for repositories that still could enter the list: at least 100 stars, not a fork, not archived, not opted out, still on GitHub. Counting the others first is what made the run of 2026-10-11 hit its two-hour limit and write nothing; 383 of the 400 candidates on 2026-09-27 were under 100 stars. Repositories with at least 5 such commits (the sample floor) and at least 100 stars are kept; forks, archived repositories and every line of .github/survival-optout.txt are dropped; the remaining ones are ordered by stars, then by that count, then by name, and the list is filled up to 100 with the hand-picked repositories kept; when fewer clear the floor, the list is shorter, not padded. The sample is a moving window (the most recent commits per signal), so a repository found one week can miss it the next without anything having changed there: every repository discovered in an earlier week that the sample missed is counted again repository-wide, with the signals it was found with, and stays while it passes the same floors. A repository leaves the list through the floors, an opt-out or its disappearance from GitHub, never through the luck of the sample; the discovery record names the ones retained that way and the ones that left. Stars first, because a raw commit count selects contribution-graph painters and mirrors of large projects, which say nothing about how AI code fares in software people use. That order exists only to choose the sample: the list file and every report page stay alphabetical. The counts behind each selection are published in .github/survival-discovery.json and each report states how its list was selected. The date in the list header is the last run that finished. A run that stops early does not replace the list; it records last_attempt in that same file, and the report says the list was not replaced.

Limits: commit search reads the default branch only, returns at most 1,000 results per query and matches text, so a message that merely mentions a trailer is a hit; the audit of the clone, not the search, decides what is counted. A commit carrying two signals counts twice in the selection count. The selection favours popular repositories where AI-attributed commits are visible; it is not a random sample of open source, and the report says so.

GITHUB_TOKEN=… python3 scripts/survival_discover.py --dry-run
# the same list, the same counts, from your own token

9Evidence classes in the ledger

Two paths, not one proof chain:

git history  →  re audit   →  survival counts
                 metadata, commit-level, method version on the JSON

hooks / proxy / record  →  .causari/ ledger  →  re why, trace, impact, lens
                 local, gitignored; declared or correlated, not authorship

A seal signs the audit JSON for one commit and one method version. It does not join the ledger to the audit, and it does not make either one a proof of who typed the code. The audit reads git. The ledger (re init, re hook, re proxy, re watch) records agent actions as they happen, and every answer it gives names one of two evidence classes.

Declared

Hooks, MCP, re record: the agent stated what it did. Exact prompt and path. With Claude Code the hook snapshots the tree right before the edit, so a human change between two agent edits is reported separately instead of absorbed.

re hook claude-code   # every prompt and edit, exactly

Correlated

Proxy + watch: the lines you inserted are searched inside completions captured moments before. A score, not a fact. The adversarial harness gives the measured numbers: 100 % on a clean write, 50 % after a formatter pass, wrong per-line attribution when two prompts touch one file in the same window.

re proxy & re watch
# model, tokens, cost; file changes joined by content

10What we do not do

Context: "Will It Survive?", arXiv 2601.16809 measures the same question on 201 projects with a different detector and finds agent-authored code is modified less often than human code. Our counts should be read next to it, not instead of it.