Back to Blog

A year of EF-Map, read back from its own decision log

EF-Map has a file called docs/decision-log.md. It is 2,355 lines long, it holds 565 dated entries, and I have never read it end to end. Nobody has. It exists so that when an agent picks up work in this repo it can find out why something is the way it is, and the only time it gets opened is to search it for one specific thing and then close it again.

I had some spare inference this week, so I pointed seven agents at it. One per period, plus a couple doing nothing but counting things. The brief was to go through the log, the git history and the anonymous usage data, and tell me what actually happened over the last year, with a commit hash or a file and line number against every claim. I then went back and checked the parts I wanted to build sections around, because a summary of a summary is where this sort of thing usually goes wrong.

What came back was more interesting than I expected. Some of it contradicts what I have written on this blog.

The shape of the year

The first commit is 12 August 2025 and it contains one file, the licence. The actual app arrives five minutes later in a second commit that also carries a 1,233,009 line JSON file of map data. Since then there have been 3,098 commits.

0200400600AugSepOctNovDecJanFebMarAprMayJunJulAug2025202667319
Table view
3,098 commits total. August 2025 and August 2026 are partial months.
MonthCommits
2025-08323
2025-09252
2025-1054
2025-11340
2025-12233
2026-01382
2026-0295
2026-0319
2026-04118
2026-0571
2026-06347
2026-07673
2026-08191
Commits per calendar month. August 2025 starts on the 12th and August 2026 covers only the first five days, so both end bars are partial months.

That March figure is not a typo. Nineteen commits in a month, against 673 in July. I knew the middle of this year had been slow but I did not know it had been that slow, and I could not have told you why without going and looking. The explanation turns out to be good, and I will come back to it.

Almost every rule in this repo was written after something broke

August 2025 was the densest month for raw activity, with 62 commits on the 30th alone, most of them tiny visual iterations on label offsets and star brightness.

Before anyone reads that as heroic, it mostly is not. The early commit counts are high because of what I was working with rather than how much I was getting done. The first version of this was built against Gemini with a fairly limited allowance, and then on GitHub Copilot, which at the time gave you frontier models with heavily truncated context windows. You could only hand it a tiny task at a time. I also did not know anything about guardrails or agent rules or how to structure a repo for this, so I was committing after every single change, purely so I had something to go back to. And I went back a lot, because a change would routinely break something unrelated. A good chunk of August and September is one small edit, one commit, and then a rollback when it turned out to be wrong. The graph is measuring caution, not output.

The other thing about that period is that the governance came later, and always in response to damage.

In early September I built a chain indexer on Cloudflare D1. It existed for four days. On 11 September I found it had generated a volume of database reads and writes I had not anticipated, paused everything with an environment flag, deleted three databases and stripped the bindings out of five config files. The whole data strategy then moved onto a Docker stack running on my own desktop, which is the direct ancestor of the Hetzner VPS everything runs on now. I started drafting the plan to get off my desktop on 1 October and actually did it on 4 December.

The pattern repeats. On 14 November a cache key was built by sticking a URL fragment on the end of a request. HTTP strips fragments, so every authenticated user collapsed onto a single cache entry and people were served other people's profile data. It was a one line fix. The file .github/security-guidelines.md, which agents are now told to read before writing anything touching auth or caching, was created hours after that fix and still carries the exact bad line as its worked example. In December a community member called Scetrov pointed out that the internal Docker services on the VPS were bound to all interfaces rather than localhost. That was not caught by me and it was not caught by an agent.

The instruction that caused an outage seven months later

On 8 November 2025 I documented, in capitals, that deploy commands must be run from inside the dist directory. That was backwards. On 8 December I reversed it. But the wrong version survived in two other documents, and on 16 June 2026 an agent followed one of them, deployed from dist, and silently shipped a build with no Durable Object binding attached. Live events went down for about eighteen minutes. The next day's audit of my own agent instructions called it the only stale instruction in the repo with a documented production outage attached to it.

The quiet months, explained

February to May 2026 is the part I genuinely could not have reconstructed from memory. The commit counts go 95, 19, 118, 71. There are no blog posts at all between 28 January and 8 June. And there is not a single dated entry in the decision log for any day in March.

Counting tools rather than commits shows the same shape from a different angle. EF-Map has 46 user-facing tool panels now. One arrived in February, one in March, one in April and one in May.

010203040AugSepOctNovDecJanFebMarAprMayJunJulAug2025202646
Table view
Panel ids from PANEL_ALLOWLIST in worker/routes/stats-usage.js, traced to first commit.
MonthTools available
2025-084
2025-099
2025-1011
2025-1114
2025-1222
2026-0126
2026-0227
2026-0328
2026-0429
2026-0530
2026-0632
2026-0743
2026-0846
Cumulative user-facing tools, dated by the first commit that introduced each tool's panel id. One tool was added in each of February, March, April and May 2026; eleven arrived in July.

There are two things going on, and the evidence for both is in the sibling repos rather than this one. CCP published the rules for an EVE Frontier hackathon on 12 February, running from 11 to 31 March. My sui-playground repo has its first commit on 14 February, two days later, and its February output is almost entirely planning documents. CivilizationControl, which became the entry, has its first commit on 12 March, the day after the hackathon opened. EF-Map itself wakes up on 1 April at six in the evening, the day after submissions closed, and the first thing it does is add a promo pill advertising the entry.

The other thing is that the game moved chains. EVE Frontier migrated from EVM to Sui on 11 March and reset the universe with it. The old event stream stopped at 13:00 UTC and the new one started at 18:00 UTC the same day, and two of the World API endpoints EF-Map depended on started returning 404. I knew it was coming. On 10 March, the day before, I shipped a section of the tools rail called "Awaiting Sui migration" that parked the four features about to break, and a ticker message that read Live events will be updated to work with Sui after 31st of March 2026, injected every 120 seconds. The comment next to it in the code says it will be easy to remove once real Sui events are live.

So the map ran degraded for about four weeks while I was building something else. That is not a story I would have chosen to tell, but it is what the record says, and the backend rebuild that followed in April is one of the larger pieces of work in the whole year.

There is a second gap in May that the repository cannot explain at all. Between 13 and 22 May there are zero commits across every repo I work in, checked individually. No entry, no document, no commit message anywhere references a break. That one was Fanfest in Iceland, and I stayed longer than I meant to because I lost my passport. Obviously none of that is the sort of thing that ends up in a commit message, which is worth remembering when you are reading any of this back. A ten day hole in the record can just be a person being somewhere else.

The tooling change that does not show up in the numbers

This is the part I was most interested in, and the answer is not the one I expected.

Commit messages in this repo carry a co-author trailer naming the model. There are 736 of them and the first is on 10 June 2026, which is the day I started using Claude Code. Before that there is nothing, because the previous setup did not write trailers. The split since then is 426 commits credited to Fable 5, 191 to Opus 4.8 across both context sizes, and 119 to Opus 5, with 2,362 commits across the whole year carrying no attribution at all.

June has 347 commits against May's 71, so the obvious story is that the new tooling caused the jump. I do not think that holds up. The ramp starts on 30 May, eleven days before the first Claude commit, with 19 commits that day and 17 the next. And if you divide by days actually worked rather than calendar days, the first nine days of June ran at 15.1 commits per active day and the twenty-one days after the switch ran at 14.1. That is flat, or very slightly down.

January 2026 also had 382 commits, more than June, on the older setup entirely. The real step change is July at 673, a month later. So my read is that the switch rode a wave that was already building rather than starting it, and that if the tooling changed anything it changed what I pointed it at rather than how much came out. The audits, the incident postmortems and the subagent work all start appearing around then. I would not claim more than that from this data.

What 673 commits actually consists of

July was the busiest month by a distance. It is not one big push and it is not mostly refactoring. There were 69 merge commits in 31 days, which works out at a bit over two shipped branches a day, and by my count 21 separate tools or features reached production.

There is a straightforward reason for the size of it that has nothing to do with discipline. July was the first full month after I moved up to the $200 a month plan, and it was the first full month on Fable 5. Inference on that plan is use it or lose it. So a fair amount of July is me inventing things to point it at, and I would not pretend otherwise. The four arcade games are the clearest example. Nobody asked for an arcade.

The thing is they turned out to matter. Each of those games takes a real on-chain payment for a revive, which meant they were hammering the Frontier Commerce payment path with small transactions for a fortnight. That is where the gas sponsor running dry against a rate limited faucet showed up, and the wallet lock error class, and a Sui outage that took ranked runs and purchases down together. All of that got found and fixed on games, where the worst case is somebody loses a run. Then EF-Map Intelligence launched on the 24th on the same rail, taking real money. So making up work to fill a subscription is probably the wrong instinct, but in this case it built the test harness for the paid product by accident.

PrefixJuly commits
feat133
docs106
fix92
chore34
refactor13
perf12
no conventional prefix277

The documentation figure surprised me until I thought about it. Almost none of those are standalone documentation jobs. They are the tail end of a feature, because this repo has a written definition of done that says a user-facing feature is not finished until the FAQ, the feature cards, the landing pages and the two llms.txt files match it. That rule costs a commit or two every time and it shows up as the second biggest category of the month.

The other number I like from July is the test suite. It sat at 725 at the start of the month, reached 1,594 by the 30th, and then went to 2,017 in a single overnight run, 281 of which were characterisation tests written against worker code that already existed. It is 2,310 now.

That curve is the clearest thing in the whole year that I would actually attribute to the models. It is not that I started asking for tests. It is that a model which can run unattended for an hour writes its own tests as part of doing the work, because it needs them to know whether it has finished. The older setup could not do that. The loop there was build a feature, test it by hand myself, come back and describe what broke, and a test suite never survives that loop because it is always the thing you skip. Going from 725 to 2,017 in a month is mostly a side effect of the work happening in longer unattended stretches.

The file that ate the project

If I had to pick one chart that explains the last year it is this one.

05k10k15k20kAugSepOctNovDecJanFebMarAprMayJunJulAug2025202620,0979,380
Table view
MonthLines in App.tsx
2025-083,184
2025-097,365
2025-109,544
2025-1110,750
2025-1212,484
2026-0114,699
2026-0215,547
2026-0315,631
2026-0416,402
2026-0517,680
2026-0620,097
2026-079,380
2026-089,503
Lines in eve-frontier-map/src/App.tsx at the last commit of each month. It grew every single month for ten months before the July 2026 decomposition.

App.tsx is the main application file. It grew every single month for ten months, from 3,184 lines to 20,097. In November 2025 I tried to extract a scene manager out of it, spent three days on it, got orphaned code and ref timing bugs that only showed up in production, and reverted the lot. The decision I recorded at the time was to leave the file alone and write documentation describing its sections instead, with a stated target of getting it under 3,000 lines. It went the other way for another seven months.

It finally came apart on 5 July, in 25 separately committed extractions done as verbatim line range moves so that each one stayed bisectable, and then again at the end of the month down to 9,380. In that same month the number of source files roughly doubled, from 353 to 729, which is where all of it went.

The difference between the attempt that failed and the one that worked was the model. Nothing about the file got easier in the intervening eight months, it got twice as long. Splitting something that size needs a model that can hold the whole thing at once and move code without quietly rewriting it on the way past, and in November 2025 I did not have that. This is the one place in the year where I would say the tooling changed what was possible rather than just how quickly it happened.

Worth saying that the documentation describing the file as 9,313 lines long was still sitting in the repo in June, when the file was 19,690 lines. It was about half right for about eight months.

There is nearly as much prose as code

source codemarkdown documentation
0100k200k300k400kAugSepOctNovDecJanFebMarAprMayJunJulAug20252026398k186k
Table view
Excludes vendored third-party code imported in September 2025.
MonthSource linesDocs lines
2025-0811,575715
2025-0972,55015,618
2025-1084,97720,523
2025-11127,38760,808
2025-12151,81563,979
2026-01187,318108,795
2026-02194,799115,024
2026-03198,126118,548
2026-04215,822146,325
2026-05239,127153,802
2026-06294,448170,110
2026-07378,462183,232
2026-08398,131186,049
Tracked lines by file type at each month end, excluding vendored third-party code. Source is .ts, .tsx, .js, .jsx and .py; documentation is .md.

Excluding vendored third party code, the repo holds about 398,000 lines of source and about 186,000 lines of markdown. I did not set out to write that much documentation and I would not have guessed it was that close to half. Some of it is genuinely load bearing, like the VPS service inventory and the deployment guide. A fair amount of it is the decision log itself, which brings me to the last thing.

The record is wrong about itself in several places

I set all this off asking for a history built out of the record. A decent chunk of what came back was the agents telling me the record could not be trusted, which was not what I was expecting but is probably the more useful result. So it is worth saying plainly how reliable it is. Not very.

There are 11 entries in the decision log dated before the repository existed. The first commit is 12 August 2025 and there are entries headed January and July 2025, which are almost certainly an LLM writing the wrong year out of habit. One of them is headed 2025-01-XX, a placeholder that never got filled in and has been sitting there ever since.

The ordering is odd too, which is what made me look at the file in the first place. The bulk of it is newest first, but new entries get appended to the bottom, so today's sit at the very end. There are 43 points in the file where the ordering flips direction.

The blog needs a caveat too. The posts dated August to October 2025 were not published on those dates. The posts.json file that drives the blog index did not exist until 3 November 2025, when it turns up in a commit that adds eight posts at once. What happened is that I started paying attention to SEO in November and wrote a batch of articles to fill in the back catalogue, and the way they were written was to point an agent at the commit history for the thing being described and have it write the article from that. So the dates are not made up, they track the git history of the work each post covers. They are backdated rather than wrong. They are also the weakest articles on the site, because an article reconstructed from commit messages reads exactly like an article reconstructed from commit messages, which is a lesson I have tried to keep in mind while writing this one. Beyond that, the transparency report I published on 31 December 2025 needed five correction commits in 24 hours, and star counts had to be fixed from "8,000+" to "24,000+" across several articles.

And the log fights back. There is a pre-commit hook that curates it automatically, and it has archived brand new entries three separate times, once because the entry's own text quoted a string the curator was filtering on. Several commits exist purely to put back what it ate. The best one is from yesterday. An agent editing the file used a Python slice that dropped everything after the insertion point, the curator then faithfully committed a decision log with 2 headings instead of 559, and the commit that fixes it is titled "restore the log I truncated" and explains the exact off by one in the message. Nothing was lost, and I only know about it because it was written down.

That is sort of the point. A record kept by agents, for agents, accumulates the same errors as any other artefact, and the only reason I can tell you about the wrong dates and the truncation and the backwards deploy rule is that the wrongness got committed alongside everything else. I would rather have this than a tidy version.

The numbers in this piece all come from the repository itself, the decision log and its archive, and the anonymous usage counters at ef-map.com/stats. If something here contradicts an earlier post of mine, this one is more likely to be right, because it was checked against commit hashes and the older one probably was not. Any of it looks off to you, tell me and I will go and look again.

Related Posts

eve frontier decision log project history git history llm development software archaeology development timeline vibe coding