Notebook

Two years, one codebase, and the agent that grew inside it

A client's map app, read back from 384 commits. A team built it, one engineer kept it alive, and for the last eight months the commits carry a model's name. One timeline holds all three.

20252026AUG 2024JUL 2026FEATURES25 SHIPPEDWORKING MAPADDRESS SEARCHFACILITY POPUPSREP LOOKUPPAGES DEPLOY119TH DISTRICTSCLUSTERING, REVERTEDDUCKDB LAYERVERIFY + SHIPCOMMITSPER MONTH, NO MERGES9560WHO COMMITTEDDEVELOPER B3921DEVELOPER C32CLIENT WEB TEAMTHE ENGINEER24292020OPUS 4.5OPUS 4.6OPUS 4.8SONNET 5

The app is a public map of industrial chemical releases. A static Next.js export, an ArcGIS map, one CSV refreshed by hand twice a year, filters for chemical groups and health harms, and a flow that turns a ZIP code into a letter to a member of Congress. A client owns it. We have built and kept it since August 2024.

Seen from the client's chair, the two years were uneventful in the best way. Review comments went in, a fixed map came back, the data stayed current. Seen from ours, the second year was a different project entirely: building an agent that could do this client's work, and using the repository as its training record. The figure above is both stories on one axis. Read the top band for what the client got, the bottom band for who did it.

Three bands, one axis

The top band is features as a user would count them: 25 things the map can do today that it could not do before, each pinned to the commit that added it. Fifteen arrive in the first hundred days. Five arrive in a single week in July 2026, and those five are drawn in brass because a model co-authored them.

The middle band is commits per month. September 2024 is a wall, 95 commits and 69 merges on top of them, and everything after November 2024 is a row of short bursts with long silences between. The median gap between bursts is 42 days; the longest is 120. Five of the bursts have the signature of a client review round: a gap of weeks, then most of the work inside three days. This was part-time work around other work, and the cadence says so without being asked.

The bottom band is who was in the room. Two other developers and a client web team in the first months. Then one name, alone, for a year. Then, from December 2025, a row of model generations: Opus 4.5, 4.6, 4.8, and finally Sonnet 5, each taking the trailer from the last. Twenty-six of the 37 commits since December 2025 carry one of those names.

It was a team first

Half the commits in the repository are not ours. 192 of 384 belong to two other developers in September and October 2024 and to two people on the client's own web team. One author is recorded, for 25 commits, as a literal shell command: a coding-school install script that had written itself into git config as a name, and that nobody noticed for a week. Twelve commits in a row carry the identical subject line. That is what a cohort build looks like in a log, and the one-engineer story only begins when the cohort leaves in mid-October.

CONVENTIONAL PREFIXHAS A BODYBODY OVER 3 LINESSAYS WHAT WAS CHECKEDTEAM · AUG–NOV 24177 COMMITS · MEDIAN 56 LINES1%2%1%1%HANDOFF · DEC 2419 COMMITS · MEDIAN 12 LINES68%11%0%0%ONE ENGINEER · 2545 COMMITS · MEDIAN 32 LINES36%24%4%7%NO TRAILER · 2611 COMMITS · MEDIAN 77 LINES0%0%0%0%AGENT · DEC 25–JUL 2626 COMMITS · MEDIAN 206 LINES46%100%81%42%
What a commit looked like in each era. The agent era is the first in which every commit explains itself; whether the explanation is true is a separate question.

The second figure is the closest thing git has to a signature. Team commits have no body 98 percent of the time and a median size of 56 lines. The engineer's own commits, alone in 2025, have a body one time in four. The agent's commits have a body every time, a body over three lines 81 percent of the time, and say what was checked in 42 percent of them. The eleven 2026 commits with no model trailer are the odd row: zero bodies, zero prefixes, and git cannot say whether a person wrote them or a trailer was stripped.

The last column deserves suspicion. It measures sentences. A body that says verified headless is a claim, and this repository had nothing that could confirm one until the final week of the record.

The first agent week made the map worse

DECEMBER 2025 · OPUS 4.5+28912/16+28012/17-20612/18-27412/22012/23NET +89 LINES · 9 COMMITSJULY 2026 · OPUS 4.8+57907/07+29707/08+4607/09+24307/10NET +1165 LINES · 13 COMMITS
Net lines of code per day in the two agent weeks. December adds a clustering feature and takes it back out; July leaves the data layer, two render fixes and a verify script behind.

December 2025 was the first burst with a model in the trailer. It added clustering and localStorage caching on the 16th and 17th, removed clustering on the 18th because it broke the build, and on the 22nd and 23rd restored the dot sizing to the values from October 2024. Nine commits, seven days, and the map ended the week behaving as it had fourteen months earlier. One of those bodies mentions checking anything. From the client's side it was a quiet week. From ours it was the first real attempt at handing the client's work to an agent, and the attempt was reverted.

July 2026 is the other bar chart. In four days the data path changed shape for the third time: the CSV now loads into an in-browser DuckDB table with a prepared-statement cache, a materialised table of per-row magnitudes so filter queries only sum a column, and one lightweight record per facility for the hot path. Two render bugs came out with it. The filter object was a fresh reference every render and the query effect was keyed on it, so every render re-queried; and the redraw was keyed on filter values rather than the data, so the filtered map did not repaint until an unrelated zoom. Both fixes are explained in their commit bodies. Nothing before December 2025 explains itself like that.

The agent checks in its own harness

The last commit of that week is the one that matters for our side of the story. Commit 370 of 384 removes debug logging and a zoom-polling timer and adds three files the repository never had: an architecture note, a Playwright smoke test, and a skill file that tells the next agent how to ship. For 23 months there had been no automated check of any kind. No unit tests, no e2e, nothing. The first one exists because the agent wrote it to guard the regression it had just fixed.

the smoke test, as a sequence
open the deployed build under its real base path
wait for the map canvas and the legend text
screenshot the canvas
switch the Chemicals filter to PFAS only
poll up to 8 s, with no zoom or pan, until the canvas changes
assert the 'dots up to N lbs' legend did not change
exit 0, write the screenshot to qa-artifacts/

Both assertions are the client's history made executable. The no-zoom poll is the July bug. The fixed legend is a review comment from 2026-07-21: dot size is normalised against the whole dataset, not the filtered set, because per-filter rescaling had misled a facility reading its own dot. The skill file around the script says, in its own words, never ship to test; drive the real interaction and see it pass first, then push, then run the same check against the live URL.

What we got wrong

  • We let a shell command sit in the author column for two years because nobody on the team was reading git, including us.
  • We shipped a week of agent work with no check beyond looking at the map, and reverted it.
  • We wrote verified into commit bodies for eight months before anything in the repository could verify a thing.
  • There are still no tests. One smoke test covers two regressions, and its screenshot goes to a gitignored folder, so even that leaves no evidence in history.

What git can and cannot tell you

The log supports the client's story completely: a team build, a handoff, one name on every commit for 21 months, in bursts that match review rounds, with the dataset refreshed on the cadence they needed. It supports ours only from December 2025, where the trailer names a model and the shape of the commits changes in a way you can measure. Before that the tooling is invisible, and eleven commits in 2026 are unsigned.

So the agent's record reads like this. First third: part of a team, and the log shows it. Middle: one engineer, tools unknown. Last eight months: its name is in the trailer, the first week was a regression, and the last week rewrote the data layer, fixed two render bugs, and left the only automated check the codebase has ever had. Each of those sentences has a git command behind it. The sentence that the work was good has one smoke test behind it, on one filter, at one URL, since the tenth of July.

The case study, from the client's side