# Build to Think: A Mid-Year Audit

*Markdown export of [the web essay](https://ummerr.com/essays/2026-to-date-build-to-think/) — 2026-08-05. Charts, screenshots and the card grid live there; this file is the prose.*

*The year-to-date audit, through the lens of [Build to Think](/essays/build-to-think/) — the **sixteenth edition** since March, regenerated with `/audit` on **Fable** and **Opus 5**, this one 2026-08-05. One ink, one accent, short on purpose.*

A golf trip needed a live scoreboard, so [one got built in an evening](https://doppler.ummerr.com) — and by Sunday the repo's closing commit read **`Seal the record: Amar wins Doppler XII on the first playoff hole.`** That weekend is the year in miniature: **1,055 commits** before work and after dinner around a day job at Google, eighteen products anyone can open in a browser, no servers to babysit and almost nothing to log into.

This week the portfolio grew a repo that quotes the others. Over one weekend, [a mapped history of every golf course ever played](https://courses.ummerr.com) and [a shot ledger for a launch monitor](https://yardages.vercel.app) arrived as two live products from one repo — and inside it, four earlier projects are cited by name: a data-staleness guard ported from the golf sim (it caught a lying mirror on its first run), a validator pattern from the archetypes build, a provenance schema from the SF atlas, and this audit itself, quoted in the spec as the reason *not* to build an integration. The notes stopped being notes. They compile now.

- **1,055** — commits · Jan 1 → Aug 5
- **18** — products live on the internet
- **$0** — monthly bill — every deploy on a free tier
- **100min** — to rebuild a product from a spec

## Lesson 1 — Projects die between sessions, not during them

Nothing here died of a hard problem. Things died of the **cold start** — sitting back down and not knowing where you left off. Every project that matured left itself a note; every one that stalled, stalled in the gap. The evidence is uncomfortably literal: one version's final commit reads `fix: resolve 27+ TypeScript build errors`; another died *finished*, on branches nobody pushed.

The pattern held everywhere: doppler seeded its `NEXT.md` the day of `git init` and matured; golf keeps a `DECISIONS.md` of forks taken with reasons; bass and archetypes v1 ended sessions mid-mess and never came back.

The new repo ran the experiment again and got the same result. Its append-only `DECISIONS.md` shipped on day one — 728 lines, 23 entries, the first project born with the convention instead of converging on it — and it reads true. Its mutable `NEXT.md` still lists **"Deploy."** as an open task, four days after the deploy, in a file whose neighboring README prints the live URL. Golf's log grew to 1,320 lines and stayed honest; golf's note fixed last edition's lie and then went stale again within hours. **The difference is structural, not a matter of discipline. Old entries in an append-only log are supposed to be old, so it cannot go stale. A handoff note is one claim about right now, so it rots the moment you stop editing it.** Put the reasoning in the log; keep the note to the one thing you'd forget — and watch the tooling too: this week the automation that writes the session stubs misfired into the wrong directory, and the repair commit *documented the misfire instead of deleting it*, which is the whole ethic in one diff.

> 📊 *[chart — The living log · how a project survives the gap]*
>
> Charts render in the web version: /essays/2026-to-date-build-to-think/

**The transfer:** give every project one living file — part lesson log, part spec: decisions with reasons, what's next, what changed your mind. Update it before you stop. Resuming beats restarting, and it scales: a team that records why it chose something stops relitigating the choice every quarter.

## Lesson 2 — Everything you build wants to become a game

Look at where each exploration *ended up*: an [atlas of San Francisco](https://sf.ummerr.com) became a [drivable city](https://rush.ummerr.com). A launch-planning idea became a [deckbuilder](https://flowslaysio.ummerr.com). Golf-course data became a [sim you can lose at](https://golf.ummerr.com). A friend's life became an [RPG](https://ummerr.itch.io/kareemrpg); even the habit tracker is a [rat you keep alive](https://rat.ummerr.com). The AI underneath is indifferent. The pull toward play comes from the person: **a general capability has no handles**, and giving it rules, feedback and stakes is how a mind gets a grip on it. Play isn't the reward for understanding. It's the instrument of it.

By late July it had a direction — golf in five repos, including a mod inside Minecraft at 2am — and the repos had begun sharing a cast: Mickey C, the tournament site's four-time champion, walked next door to become the sim's protagonist. This week the cast grew to four — Sal, Kyle and Conor joined, one file each, and the type system holds the ensemble together: adding a game event *fails to compile* until all four have something to say about it. And then the pattern inverted. The sixth golf repo is **not a game — it's a lab**: the same obsession that produced a 16-bit sim on real courses now measures every course played and every range shot hit, with sources. Even its name came out of the cluster's own data — Alister MacKenzie, whose Meadow Club sits third on the list the map is built from, a fact that entered the portfolio months ago as a row in the SF atlas. Play built the appetite; the appetite built an instrument.

**The transfer:** when an idea isn't landing — a pricing model, a roadmap — build a toy version people can *lose* at. Losing teaches faster than reading. Then watch what the play makes you curious about: the questions a game leaves you asking are a better roadmap for the serious tool than the requirements you'd have written up front.

## Lesson 3 — Build the memory first, then chisel the product out of the rest

Building to think works like sculpture: early versions pile up material — code, dead ends, notes — and the product is what's left after you cut the rest away. The cutting is only safe if the design lives somewhere outside the code. That's why the memory comes first.

The Dopamine Rat proves it. Built four times; dependencies per version ran **2 → 7 → 10 → 3.** The version that shipped is the smallest, and the only one that started from a written record of what the first three got wrong. Doppler applied the rule on day one instead of attempt four: two dependencies, no backend, and 264 CI data invariants — the key one *"asserts the tournament record agrees with itself."* **If a number can be derived, derive it**; anything hand-set is labeled as opinion. The same move works on whole repos: the SF atlas deleted the driving game growing inside it — copied out first, so the deletion stayed reversible — and the Minecraft mod was deleted and rebuilt in ~100 minutes because its design already lived in a spec.

The new repo is the rule's most extreme statement yet. The course map's `package.json` has **no dependency section at all** — 4,000 lines of site and pipeline on zero installed packages, the map library loaded from a CDN. The shot ledger runs four runtime dependencies and 268 tests. A database was in the original design and got deleted before it shipped, with the reasoning on file: two years of range sessions is 1.5 MB of JSON, *"Postgres was solving no problem here"* — and the table that existed so parser fixes could be replayed over history was replaced by the observation that **git already does that**, with real diffs and better provenance. The same discipline held at [stems](https://stems-nu.vercel.app) in July: ~5,000 lines of video export, a hand-written FFT and a full Winamp skin, zero new dependencies, guarded by an eleven-item list of things that look like dead weight and aren't, each ending *don't "simplify" it back*.

The memory half got its sharpest artifact yet: the ledger's **bag file**. Every number on the page is derived from a recorded shot — and that's the flaw, because a club with no shots renders as *nothing to report* when the truth is *never measured*. On the real data that hid four of thirteen clubs. So the bag is asserted by hand and committed: the one fact the record structurally cannot derive is the one fact that gets written down — and writing it down is scored honestly as opening a question, not closing one; every asserted loft ships marked unverified.

> 📊 *[chart — One repo, three homes · the July extraction]*
> Maturity as separation of concerns you can survive: give each exploration its own address, and keep — don't destroy — what it grew out of.
>
> Charts render in the web version: /essays/2026-to-date-build-to-think/

## Lesson 4 — AI compressed implementation. It did not compress judgment

The cold start is how projects die; whether the thing deserved to exist is why you never come back. **[bass](https://bass.ummerr.com)** is the year's honest failure: ten commits of supply for a demand that never existed — one practice ever logged. The code was fine. The decision was wrong, and every added feature compounded it. Rat v3 made the same mistake with more ceremony — Garmin OAuth before daily use was proven — and died *finished*. film died in a day, zero photos.

The successes were decisions too: delete 19,963 lines from the atlas, cap doppler's dependencies on day one, let the renderer admit what the map doesn't know. Implementation got cheap this year — an evening buys what a quarter used to. Judgment didn't, and it's the skill this portfolio was actually training.

This week's evidence is a run of refusals aimed at the instrument itself. The launch monitor wrote the carry distance into the total-distance column, verbatim, on 51 of 255 shots — *"that is not a ball that stopped where it landed"* — and the ledger reads those totals as **absent**, taking the cost in the open: three clubs go dark on total, because a club measured only by shots with no rollout information has not been measured. A score sitting in the wrong column gets flagged, never edited — *"silently doubling them would invent data."* A low carry isn't a mishit if the swing was soft on purpose: *a partial is not a mishit*, and no shot is ever excluded for a metric the monitor failed to record. Even the column names aren't trusted: a firmware update could swap two columns and every sentence would stay plausible while being wrong, so the physics that ties them together — curvature to spin axis, start line to club face — is asserted in tests, and **a relabelled column now fails the suite.**

**The transfer:** when something you built isn't being used, don't add features — read the verdict. Non-adoption is data about the decision, not the polish. And when a dashboard's number looks clean, ask what the instrument would show you if it were lying: the dangerous defaults are the ones that produce a plausible value instead of an error, and the fix is an assertion that fails loudly, not a correction that hides the doubt.

## The stack — whatever you don't have to log into wins

The monthly infrastructure bill is $0 — but the money is the least of it. Sort the portfolio by what each project *depends on* and a pattern falls out: **everything that survived runs on things you can hit without logging in** — OpenStreetMap, MapLibre, git, `localStorage`, a static host's free tier — and **everything that rotted, rotted at an auth boundary**: an OAuth flow, an expiring token, a service key. Not because open tools are better, but because they're still there at 5am, on a phone, from a golf course. The path of least friction wins, and a login screen is friction.

**Keyless → still running**

- OSM + Overpass — two golf projects' course geometry; cost: an attribution line
- MapLibre — real maps, no API key
- Open-Meteo — live microclimates for the atlas’s weather-chase mode; no key
- git + a CDN — doppler's whole "backend"; scoring is a commit
- localStorage — the rat's database; the flagship's job queue
- Jekyll + GitHub Pages — twelve years; its one death is opposite →
- NRCan HRDEM — 1 m LiDAR terrain for the Niagara courses; an unauthenticated search, no key
- Nominatim + Esri imagery — the new course map's geocoding and basemap; every source in its spec lists Auth: none
- Demucs, local — stems: no cloud, no accounts, no uploads; the price: only a demo lives at a URL

**Auth-walled → where things rotted**

- Garmin OAuth — built before daily use was proven; rat v3 died finished
- a Supabase anon key — five months of public writes on the flagship
- Universal Analytics — the site's one death in twelve years
- cron secrets & DNS aliases — the rat simplified; the failures moved here
- a stale Overpass mirror — the one that answers looks healthy; three courses baked from May data. Sequel: the guard written after that caught a second mirror lying 50 days deep — in a different repo, on its first run

Tournament weekend was the field test. Thursday, July 23: `git init` at 3pm, a live tournament site by 11:31pm. Then every update, all weekend, came **from a phone between rounds** — 22 commits of scorecards entered hole by hole from the course in Ontario. **Nothing on the board was ever set by hand**: standings, odds and the champion badge all derive from the committed scorecards. No admin panel, no login. That's the bar — *run it from a golf course, on a phone, between shots* — and any OAuth screen in that path kills the live board by Saturday.

The thesis has a control arm: a fresh problem went to a different agent — **OpenAI Codex** — and came back as a [golf-course digital twin](https://course-render.vercel.app), which on day two added a Supabase tier with logins, the stack's first new keys in months. Two editions later the pattern is data: the twin's one commit since was a 29,000-line test fixture and a rendering split — real work — while its auth tier went untouched, and its API surface now answers 404 from outside. Nothing rotted loudly. Auth-walled things don't; they just stop being checkable.

But keyless is not the same as trustworthy. The free endpoint that asks nothing of you can still hand you two-month-old data with a straight face — which is exactly what happened below. **Open beats auth-walled on survival; neither one buys you correctness.** The fix isn't a key, it's a freshness check.

**The transfer:** count the credentials before you count the features — every key is a place the project can die while you're not looking. Then go back and ask each keyless source how you'd *know* if it started lying. The ones that ask nothing of you also promise nothing to you.

## What building on top found

Seven courses went into the golf sim in one evening. That meant leaning on parts of the pipeline nobody had leaned on, and three things fell out — each of them shipping silently since the day it was written.

- **The parser had been dropping data.** OpenStreetMap describes a shape as either a single way or a multi-part relation. The code asked for both, then skipped every relation. The query *looked* healthy; it returned rows. **Torrey Pines South had been shipping with zero fairways.**
- **The map mirrors had been serving months-old data.** The primary endpoint was rate-limited, the script failed over exactly as designed, and the backup answered with a **June 1 snapshot**. Nothing in the response said so. Three of eighteen courses baked from stale data in one run.
- **Five messages had never once appeared on screen.** `SPLASH`, `OUT OF BOUNDS`, `CLONK`, `BEACHED`, `ON IN n` — set, then overwritten in the same tick by the line after. Found only because the new character needed the same channel to speak through.

The sequel landed five days later, in a repo that didn't exist when those bugs were found. The staleness guard written after the mirror incident was ported into the new course map — and on its **first run** it refused a mirror serving 50-day-old data. That's the difference between a lesson learned and a lesson installed: one lives in your head, the other fires in a repo you haven't started yet.

**The transfer:** when you inherit a pipeline you didn't write, don't audit it — *extend* it. Tests check the paths you thought of; the next feature walks into the ones you didn't, and it's free, because you were going to build it anyway. The same trick works on a system you inherited at work: the fastest audit of code nobody remembers is the next thing somebody needs from it.

## The year in one line

> 📊 *[chart — The shape of the year · commits per week, in three acts]*
>
> Charts render in the web version: /essays/2026-to-date-build-to-think/

Two quiet months, a detonation, then a tail that keeps accelerating. July's real final number is **267 commits** — the year's #3 month, and fifteen more than the last edition printed, because that edition was generated at noon on July 31 and the day kept going; its own publishing commits are part of the difference. A census is an intervention, and this one says so. March-and-April's share is down to **56.3%**, eroding every edition without a single spring commit changing. Neither dip in the middle is a stall: the mid-May flatline is **Google I/O**, the sprint before the keynote taking the same pre-dawn margins; the June trough is a **move across the country**, New York to San Francisco. Building happens at **5am** and after 8pm, almost never during the workday — the two peaks still exactly level at 95 commits each. August's first anomaly: the new repo was built in *daylight*, mid-morning and evening across a weekend. The 5am clock was never a preference; it was the shape of the free time.

## The portfolio

**This round's deltas** — [**MACKENZIE + Yardages**](#mackenzie) · [**MUNI golf**](#golf) · [**course renderer**](#courserender) · [**the site**](#site)

**Shipped &amp; steady** — [The Doppler XII](#doppler) · [bookmarks](#bookmarks) · [archetypes](#archetypes) · [SF](#sf) · [Flow Slays IO](#flow-ascent) · [inference](#inference) · [stems](#stems) · [Level Atlas](#levels) · [Minecraft mods](#mods) · [kareemrpg](#kareemrpg) · [prompts-mcp](#agents)

**Bench &amp; footnotes** — [SF Rush](#rush) · [the Dopamine Rat](#dopamine-rat) · [bass](#bass) · [the bench](#footnotes)

- **[MACKENZIE + Yardages](https://courses.ummerr.com)** · NEW · 27 commits · Aug 1–3 · two products live — Every course ever played, mapped with sources — 84 facilities, zero dependencies — and a shot ledger that reads a launch monitor's exports with open distrust: 255 shots, 74 excluded with stated reasons, 268 tests, and a generated profile where every finding names what would falsify it. Built in a weekend on four other repos' written-down lessons.
- **[The Doppler XII](https://doppler.ummerr.com)** · 108 commits · Jul 23–28 · record sealed — Built in one evening, operated from the tournament, sealed by Sunday. Live scoring was literally git: commit a scorecard, the field’s phones update. Two runtime dependencies, no backend, 264 data invariants in CI. After the seal came “The 36th”: the playoff hole resurveyed from OpenStreetMap, shot by shot, with witness corrections amending the record. Its roster file turned out to be a casting file — the champion is now the playable character in the golf sim next door.
- **[SF Rush](https://rush.ummerr.com)** · built inside sf, Apr–Jun · own repo since Jul 12 — Don't read the commit count — the game was built across sf's spring sprints, then copied out whole on Jul 12: 18k lines, six vehicles, real LiDAR terrain. The chart shows the full lineage; its default level is now the Harbor Links golf course.
- **[Flow Slays IO](https://flowslaysio.ummerr.com)** · 27 commits · Jun–Jul · shipped — A Slay-the-Spire deckbuilder about shipping a GenMedia model. The truest mechanic: the PM classes cannot deal damage — the whole kit is leverage on other people’s cards. July’s retheme added pixel-art combat and an honest balance simulator — launch-week runs were near-unwinnable; now 30–70%.
- **[Prompts · the flagship](https://prompts.ummerr.com)** · 282 commits · Feb–Jul · shipped — X bookmarks → a curated gen-media prompt dataset a Google PM actually uses. Best artifact: a prebuild gate where a hallucinated fact becomes a failing build. July closed a 5-month-open public-write hole in one migration.
- **[Archetypes](https://archetypes.ummerr.com)** · 172 commits · Mar–Jul · shipped — v1 was built entirely on a phone. v2 rebuilt the problem statement: 87 archetypes, 170 graded mappings, every objection attacked on schedule and the survivors published.
- **[Course renderer](https://course-render.vercel.app)** · Δ · 11 commits · Jul 27–31 · built with Codex — A golf-course digital twin on MapLibre + OpenStreetMap — refuses to invent geometry the map doesn’t know. The keyless thesis's control arm: this round it gained a 29,000-line Olympic Club stress fixture while its auth tier sat untouched — not broken, just no longer checkable from outside.
- **[Stems](https://stems-nu.vercel.app)** · 25 commits · Jul 19–30 · demo live — A local-first Demucs stem splitter whose demo renders music videos in your browser — ten styles, four generative sketches drawn from a hand-written FFT — and then, in twenty-three minutes, became a working Winamp: bevels, a real spectrum analyser, a ten-band EQ wired as actual audio. Its dependency list hasn’t moved since July 28.
- **[Level Atlas](https://levels-cyan.vercel.app)** · 8 commits · Jul 30 · live — An atlas of level design in which the repo is the database: eight levels, thirteen techniques, every entry a JSON file checked at build time, so a dangling reference fails the build instead of the page. Day two it deleted its placeholder map and built a space-graph engine instead — one vocabulary that draws a 1985 side-scroller and a 2016 immersive sim from the same data.
- **[The SF atlas](https://sf.ummerr.com)** · 123 commits · Apr–Jul · shipped — An atlas built to answer a real question: where in SF to live. Its weather-chase mode colors 189 neighborhoods by live sun, wind, and warmth and ranks the best ones within reach — microclimates as a decision tool for the move. It also grew a driving game, then gave it up: −19,963 lines in six reversible minutes.
- **LabsCraft v2 · minecraft-mods** · 14 commits (+6 on a branch) · Jan–Jul — An LLM-driven NPC mod deleted (−10.5k lines) and rebuilt (+12.5k) in ~100 minutes by 7 parallel agents — safe because the design was extracted into a spec first. On Jul 28 agents added a third mod in 21 minutes: SportsCraft, golf inside Minecraft — PR open, honest that no one has run it yet.
- **[Inference](https://inference.ummerr.com)** · 64 commits · Apr + Jul · shipped — Gen-AI unit economics, cited and interactive. Its 34-commit launch day exposed the missing source of truth; the fix made July’s refresh one commit instead of thirty.
- **[MICKEY'S MUNIS · golf](https://golf.ummerr.com)** · Δ · 35 commits · May–Aug · 20 real courses — A 16-bit sim on real course geometry — 342 holes, from Augusta to a Toronto par 3, still two runtime dependencies. This round every hole got a shareable address (one prerendered page each, hand-rolled router), the cast grew to four characters the type system keeps in voice, Kamloops arrived via real data archaeology — the club had renumbered its nines after the course was mapped — and courses 19 and 20 were baked and merged by a cloud agent on the CI runner.
- **[The site](https://ummerr.com)** · Δ · 96 commits · shipped since 2014 — The workshop’s logbook — and this audit’s publisher. Survived twelve years by having nothing that could rot. As of this edition it is also cited by the work it measures: the newest repo quotes the audit as the reason to skip an integration.
- **[The Dopamine Rat](https://rat.ummerr.com)** · 49 commits · 4 rebuilds · v4 live — Dependency count per version: 2 → 7 → 10 → 3. v4 wins by deleting the other three and building its continuity doc before any feature.
- **[kareemrpg](https://ummerr.itch.io/kareemrpg)** · Godot · shipped · a birthday gift — A friend’s life as a walkable RPG. The tutorial folder quietly became the product — bias toward extending what works.
- **[bass](https://bass.ummerr.com)** · 10 commits · Apr · one logged practice — The year's honest failure, and Lesson 4's exhibit A: a perfect practice tool that consumed the practice slot.
- **prompts-mcp** · 6 commits · shipped — Learned MCP by implementing all four primitives and both transports over his own dataset. The bugs were the curriculum.
- **The bench** · film · VidMetaPrompt · cursorMint — film died in a day with zero photos; two repos never reached a first commit. Cold-start deaths, cheapest form.

## The cadence

> 📊 *[chart — The bimodal builder · commits by hour of day (Pacific)]*
>
> Charts render in the web version: /essays/2026-to-date-build-to-think/

> 📊 *[chart — Every day of 2026 · Daily commits, week by week]*
> Hover any day for its count and which repos moved. The dense block is the March–April detonation; the warm cell is the single busiest day (Apr 12, the inference launch).
>
> Charts render in the web version: /essays/2026-to-date-build-to-think/

## The verdict

The portfolio isn't a list of products; it's a **thinking log with a URL for each thought.** The constraint was never ideas or energy — it was continuity, and for seven months the system built against it was defensive: leave a note, keep a decision log, so the next session doesn't start cold.

This edition the logs went on offense. A guard written after one repo's data went stale fired in a repo that didn't exist yet. A validator pattern, a provenance schema and an auth post-mortem crossed repo boundaries as working parts, not anecdotes. The write-up turned out not to be overhead — it's the part that ships twice. Even the audit's own error this round fits: July's "final" count was off by fifteen because the report was published into the middle of the day it was counting, and its own publication was part of the difference.

What none of this has been tested on is other people. Every citation in that grid is one person quoting themselves — the decision log is never disputed, the campfire convention is never someone else's, and no one has ever argued that the flagged data should be corrected after all. Solo, the system compounds. Whether it transfers to work where the log has co-authors is the question a solo portfolio structurally cannot answer, and the back half of the year still owes an experiment on it.

Build to think; then write it down, because the note you leave is the only part of a build that can show up early for the next one.

---

*Sixteenth dated edition since 2026-03-29. Census through 2026-08-05. Regenerated with `/audit` on **Fable** and **Opus 5** across the run — this one on Fable. The long-form master report lives at `~/CodeProj/PROJECT_AUDIT.md`.*
