Inhalt (9 Abschnitte)
- 1. Stichprobe: welche Commits es wert sind, erzählt zu werden
- 2. Nachbauen: Das Problem ist nicht der Code, sondern die Epoche
- Die vier Fallstricke, die am meisten Zeit kosten
- 3. Fotografieren: die Falle des inneren Scrollens
- 4. Zählen ist Aufgabe von Git, nicht eines Modells
- 5. Erzählen, dann prüfen
- Was die Ausführung gefunden und das Review übersehen hat
- Der Meilenstein, der nie gestartet ist
- Was es kostet, was es bringt
Es gibt eine Frage, die fast kein Team mit Belegen beantworten kann: Wie sah das Produkt vor achtzehn Monaten aus? Die Mockups wurden überschrieben, die Screenshots liegen verstreut in Chatverläufen, die Abnahmeumgebung wurde dreimal neu aufgebaut. Dabei ist die Information unversehrt vorhanden, nur ein paar Meter entfernt: im Git-Repository.
Wir haben ein Werkzeug geschrieben, das sie nutzt. Es durchläuft die Historie, wählt Meilensteine aus, baut jeden davon in Containern mit dem SDK und der Datenbank seiner Zeit nach, startet die Anwendung, fotografiert ihre Seiten, zählt die Fakten mit Git und setzt daraus ein Dokument zusammen. Es lief über zwei Jahre Historie der Plattform BuyStep und hat fünfundzwanzig echte Screenshots erzeugt. Im Folgenden: wie es aufgebaut ist und vor allem, welche Probleme zu lösen waren.
1. Stichprobe: welche Commits es wert sind, erzählt zu werden #
1.700 Commits nachzuspielen, wäre sinnlos. Die gewählte Regel ist absichtlich simpel: ein Meilenstein pro Monat, dazu einer pro festgelegtem Ereignis (Versionswechsel des Frameworks, Wechsel der Datenbank-Engine, Entstehung eines Portals). Ein monatlicher Meilenstein, der weniger als sieben Tage von einem Ereignis entfernt liegt, fällt weg, damit dieselbe Woche nicht zweimal erzählt wird.
Zwei Details machen in der Praxis den ganzen Unterschied. Erstens sind die Analysefenster lückenlos und überschneidungsfrei: Jeder Commit der Historie gehört zu genau einem Meilenstein, sonst werden Zahlen doppelt gezählt. Zweitens hat jeder Meilenstein mehrere Kandidaten für den Nachbau, sortiert nach der Wahrscheinlichkeit, dass sie kompilieren: zuerst die Merges von Pull Requests, dann die First-Parent-Commits, dann der Rest. Der erste, der startet, gewinnt.
2. Nachbauen: Das Problem ist nicht der Code, sondern die Epoche #
Einen Commit auszuchecken, ist trivial. Ihn zum Laufen zu bringen, nicht: Das SDK von damals ist nicht mehr das installierte, die Datenbank-Engine hat sich geändert, und die referenzierten Pakete lassen sich nicht alle gleich installieren. Die Abfolge für jeden Kandidaten:
git worktree add --detach <tmp>/<sha> <sha> # Wegwerf-Arbeitsverzeichnis, das Repository wird nie verändert
# Erkennung der Epoche: TargetFramework der .csproj, referenzierter EF-Core-Provider, vorhandener Ordner apps/
docker compose -f compose.<moteur>.yml up -d # frische Datenbank, anonymes Volume, eigener Port
docker run --rm -v nuget-cache:/root/.nuget <sdk-de-l-epoque> dotnet publish
dotnet ef database update # die Migrationen von damals, nicht die von heute
# schematolerantes Einspielen der Daten, dann Laufzeit-Container, dann BereitschaftsprobeDie Erkennung der Epoche ist das Herzstück des Aufbaus, und sie wird aus dem Commit selbst abgeleitet, nie aus einem fest codierten Datum. Bei BuyStep unterscheidet sie vier Zeiträume: .NET 8 auf MySQL, .NET 9 auf MySQL, .NET 9 mit zwei getrennten Datenbanken (Anwendung und Dateien), dann ab April 2026 .NET 10 auf PostgreSQL mit einem Node-Portal.
Das Einspielen der Daten muss schematolerant sein: Der Datensatz von 2026 passt nicht in die Tabellen von 2024. Konkret wird jede Einfügeoperation versucht und übersprungen, wenn die Spalte noch nicht existiert. Das ist hässlich, aber das Einzige, was über fünfundzwanzig verschiedene Schemata funktioniert.
Die vier Fallstricke, die am meisten Zeit kosten #
- Secrets, die Pflicht geworden sind. Eine Anwendung, die 2024 ohne Zahlungsschlüssel startete, verweigert 2026 den Start, weil ein Dienst angefangen hat, die Variable zu verlangen. Der Ausweg ist nicht, ein echtes Secret zu liefern, sondern einen Wert im richtigen Format: Die Seiten werden angezeigt, nur ein echter Aufruf würde scheitern.
- Paketlizenzen. Eine kostenpflichtig gewordene Mapping-Bibliothek prüft beim Start ein Token. Im betroffenen Zeitraum reicht ein Dummy-Wert nicht: Man braucht den echten Schlüssel, sonst starten diese Meilensteine nicht. Das sollte in den Fehlermeldungen explizit stehen, sonst sucht man eine Stunde lang.
- Abhängigkeiten, die den Prozess beenden. Ein Indexierungsdienst, der die Anwendung anhält, wenn seine Suchmaschine fehlt, macht aus einem nachbaubaren Meilenstein ein stilles Scheitern. Entweder wird der Dienst gestartet oder seine Initialisierung abgeschaltet.
- Ports. Eine Entwicklungsdatenbank läuft bereits auf dem Rechner, und der nachgebaute Stack verbindet sich mit der falschen. Eigene, konfigurierbare Ports, und nie die des Projekts.
3. Fotografieren: die Falle des inneren Scrollens #
Die Screenshots entstehen, während der Stack läuft, in 1440 × 900 bei doppelter Pixeldichte, ganzseitig, mit abgeschalteten Animationen und einem vorherigen vollständigen Durchscrollen, um das verzögerte Laden der Bilder auszulösen. Zu jeder Datei gehört eine Schwesterdatei .meta.json: Status, tatsächliche Seitenhöhe, Textlänge des Dokuments, Notizen.
Diese tatsächliche Höhe ist keine Dekoration: Sie ist eine Produktkennzahl. Bei BuyStep sinkt sie von 11.620 Pixeln im August 2024 auf 5.514 im April 2025, steigt einen Monat später wieder auf 13.624, erreicht im Frühjahr 2026 15.110 und fällt im August 2026 auf 8.302. Die Reihe der Höhen erzählt für sich allein die redaktionelle Geschichte der Website.
4. Zählen ist Aufgabe von Git, nicht eines Modells #
Das ist die Designentscheidung, mit der wir am zufriedensten sind. Bevor überhaupt ein Sprachmodell zum Einsatz kommt, erzeugt eine kostenlose Offline-Stufe die Zahlen für jedes Fenster:
# Commits pro Autor, arbeitsreichster Tag, nächtliche Commits, Reverts, gemergte PRs
git log --no-merges --pretty=format:%H%x09%an%x09%aI%x09%s <depuis>..<jusqua>
# hinzugefügte Migrationen, Änderungen an Abhängigkeiten, betroffene Bereiche des Repositorys
git diff --name-status <depuis>..<jusqua>
git diff <depuis>..<jusqua> -- "*.csproj" "package.json"Die so erzeugte Faktendatei wird den Agenten anschließend übergeben. Sie müssen nur noch auswählen, was erzählenswert ist, und es formulieren. Ein Modell, das Commits in einem Log zählen soll, irrt sich; ein Modell, dem man die Zählung liefert, kann sich dabei nicht irren. Die Grenze ist leicht einzuhalten: Was sich mechanisch prüfen lässt, darf nie durch ein Modell laufen.
5. Erzählen, dann prüfen #
Die Schreibstufe ist in vier Rollen aufgeteilt, jede dem günstigsten Modell anvertraut, das die Arbeit schafft: die markanten Fakten extrahieren und ihrem Commit-Hash zuordnen; die visuelle Änderung zwischen zwei aufeinanderfolgenden Screenshots beschreiben; den technischen Teil zusammenfassen; die durchgehende Erzählung schreiben. Ein fünfter Durchgang prüft das Ergebnis gegen die in der vorigen Stufe gezählten Fakten und markiert, was darin nicht belegt ist.
Die Antworten werden auf der Festplatte zwischengespeichert: Ein Neustart der Kette bezahlt nicht noch einmal, was schon berechnet wurde. Bei einem Projekt über zwei Jahre ist das der Unterschied zwischen einem Werkzeug, das man nutzt, und einem, das man einmal startet.
Was die Ausführung gefunden und das Review übersehen hat #
Das Werkzeug selbst wurde schnell geschrieben, von mehreren Agenten, die parallel an getrennten Modulen arbeiteten, mit einem vorab geschriebenen Schnittstellenvertrag und einem Reviewer pro Modul. Der Code wurde geprüft, und das Review fand nichts Schwerwiegendes. Dann haben wir es auf echte Commits angesetzt, und in wenigen Minuten tauchten vier Fehler auf: die durch inneres Scrollen abgeschnittene Seite, eine Migration, die eine Factory verlangte, die es damals nicht gab, ein Indexierungsdienst, der die Anwendung anhielt, ein bereits belegter Port.
Keiner dieser vier war ein Logikfehler. Alle waren Fehler beim Kontakt mit der Wirklichkeit: eine Annahme über die Umgebung, nicht über den Code. Genau diese Art von Fehlern findet kein Review, ob von Menschen oder nicht, und deshalb nennen wir eine Funktion nie fertig, bevor wir sie laufen gesehen haben.
Der Meilenstein, der nie gestartet ist #
Von sechsundzwanzig Meilensteinen hat sich nur einer widersetzt: Anfang März 2025. Sein Migrationssatz enthält echte Fehler (eine Spalte, die auf eine ID eines anderen Typs verweist, eine doppelt deklarierte Integritätsbedingung, ein Datensatz, der vor seiner Elternzeile eingefügt wird), und alle vier Kandidaten-Commits teilen sie.
Wir hätten die Suche ausweiten können, bis ein Commit kompiliert. Wir haben es nicht getan, weil das Repository selbst entschieden hat: Fünf Tage später setzte es diese Migrationen vollständig zurück. Das gescheiterte Nachbauen ist keine Lücke in der Dokumentation, sondern eine Zeile darin. Ein solches Werkzeug muss sagen können: „Das startete nicht, und zwar aus diesem Grund“; wenn es beschönigt, ist es nutzlos.
Was es kostet, was es bringt #
Rechnen Sie beim ersten Durchlauf mit drei bis acht Minuten Nachbau pro Meilenstein, danach deutlich weniger dank Image-Layern und einem gemeinsamen Paket-Cache, und mit rund fünfzehn Gigabyte Festplattenplatz. Bei sechsundzwanzig Meilensteinen ist das eine Nacht Rechenzeit. Die Zählstufe ist kostenlos; die Schreibstufe kostet ein paar Euro an Tokens.
Dem gegenüber stehen: eine Fallstudie mit echten Bildern statt Stockfotos, datierte technische Entscheidungen, wenn man sie begründen muss, eine Übergabe, die nicht mehr vom Gedächtnis derer abhängt, die gehen, und (ein Nutzen, mit dem wir nicht gerechnet hatten) ein hervorragender Detektor für Schwachstellen. Ein Repository, dessen Stand von vor sechs Monaten sich nicht nachbauen lässt, ist ein Repository, dessen Umgebung man nicht mehr beherrscht.
Diese Art von Werkzeugen bauen wir für unsere Kunden zusammen mit ihrer Anwendung: Continuous Integration, Containerisierung und Reproduzierbarkeit sind keine Extras für das Projektende. Wenn Ihre Plattform diese Behandlung verdient, sprechen wir darüber: Erstgespräch kostenlos, Angebot binnen 48 Stunden.



