Lossless Changelog

The ledger learns what the changelog never said

Commit volume and the model timeline now sit under the entry marks, so the strip shows what was built and what it was built with — not just what got written down.

Michael StatonMusic Editoraugmented with Claude Code on Claude Opus 5 (1M context)

The ledger learns what the changelog never said

Why Care?

Yesterday's ledger had one honest flaw: it could only show what someone had bothered to write down. 393 entries is a real record, but it is a record of documentation, and documentation is the lagging indicator. The work itself lives in 4,339 commits.

So the strip now carries three series on one axis, and they answer three different questions:

  • the area — what we built

  • the marks — what we wrote down

  • the band — what we built with

Where the area rises with no mark above it, code shipped and nobody logged it. Where the band changes colour, the frontier moved and the whole working method changed with it. Neither of those is visible in a changelog alone.

What's New?

Code volume beneath the entries. 4,339 commits and 5.9M lines across 36 repositories, drawn as a low-opacity area under the hairlines. pnpm sync:commits refreshes it, kept separate from pnpm sync because the GitHub stats endpoints are slow and rate-limited in a way the contents API is not.

A model timeline. 307 entries record which model did the work, and the eras recover the last eighteen months of frontier-chasing: Opus 4.5 → 4.6 → 4.7 for a long stretch, then 4.8, Sonnet 5, Fable 5 and Opus 5 all inside the final eight weeks. It reads as a band beneath the strip, sharing its x-axis.

Outbound links on every project. A GitHub mark on all thirty-eight rows, and a splash-page mark on the eleven that have one — dim at rest, brighter on row hover, full on direct hover. Never hidden: which projects have a splash is itself information, and hiding it until hover means the only way to learn it is to sweep the mouse down the list.

This site tracks itself. lossless-changelog is now a stream in its own manifest, which is either tidy or recursive depending on your temperament.

How it works

Model attribution is a normalization problem, not a lookup. The augmented_with field is hand-typed at the end of a working session, so it arrives as "Claude Code on Claude Opus 4.7 (1M context)", "Claude Code (Opus 4.7)", "Claude Opus 4.5", and plain "Claude". src/lib/models.ts parses family and version out of that, and returns nothing rather than guessing when a value names no model — 24 entries say only "Claude", which is not enough to place on a timeline and is better left blank than invented.

Colour in the band encodes model family, not recency. The temporal ramp already owns time across this whole site; saying two different things with one vocabulary would make both unreadable. The families draw from the brand spectrum tokens, which had been sitting unused since the extraction.

Weeks with no augmented entry draw nothing. A gap in the band means "no record", not "no model" — absence of evidence, and the chart should not claim otherwise.

Under the Hood

The premise this started from was wrong, and the data said so. The commit layer was requested on the understanding that we committed diligently for roughly nine months before we started writing changelogs, so the ledger understated when the work began.

It does not, and the strip does not extend leftward. Every lossless-group repository in the manifest was created in or after March 2025 — lossless-site and lossless-monorepo both on the 21st — and the earliest commit in any of them lands 2025-02-16. The earliest changelog entry is dated 2025-01-18, which predates every repository's existence, so it is a backdated retrospective rather than evidence of a longer record. Whatever the pre-March work was, it is not in these repos.

What the data does show is the same point distributed rather than prefixed: 29 of 69 active commit weeks carry no changelog entry at all. That was briefly a headline stat until it became clear it was measuring the wrong thing — this corpus is largely one person working at the edge of agentic engineering, not a team with a documentation obligation, and "undocumented weeks" framed as a scold is a non-finding wearing a suit. The helper survives in lib/commits.ts; it is just not the headline. Throughput is.

Two traps in the stats API. /stats/contributors returns an empty body while GitHub computes it asynchronously — treating that as "no data" would have silently recorded every repo as zero commits, so the sync polls with backoff and records unavailable as unavailable. And its week keys are Sunday 00:00 UTC, which had to be matched exactly for the two series to align; verified against 483 day-probes rather than assumed.

Stats are per repo, changelogs are per path. memopop-ai, memopop-native, and memopop-site are three streams reading one repository at three different paths, and GitHub cannot attribute a commit to a subdirectory. They necessarily share a commit series, so global totals aggregate over unique repos or the trio would be counted three times.

Adding the links needed the row rebuilt. It was the anchor, with the name and sparkline nested inside it, and an <a> inside an <a> is invalid HTML that browsers recover from unpredictably. Extracting ProjectRow.astro fixed that and collapsed three near-identical copies of the row markup into one. It also surfaced a rule that had silently stopped matching: Astro scopes styles per component, so once the row moved out of the page, the page's .kids > li > .row indent could no longer reach it.

What's Next

  • Push-triggered ingest — one org-level webhook, with the cron sync as the self-healing fallback.

  • Splash detection on a cadence. The eleven splash URLs were probed by hand; a project shipping one tomorrow will not appear until someone re-runs that check.

  • DESIGN.md, so the rest of the rebuild reads a contract instead of re-deriving it from CSS.