Kann ein KI-Agent ohne vollständigen Codekontext arbeiten?
Warum vollständiger Codekontext entscheidet, ob KI-Agenten verborgene Abhängigkeiten finden, Legacy-Verhalten erhalten und Batchläufe überstehen.

Ein KI-Agent, der nur eine Datei sieht, kann eine lokal überzeugende Änderung vornehmen und trotzdem das System beschädigen. Meist scheitert es nicht an fehlerhafter Syntax oder einem offensichtlich falschen Zweig. Es fehlt ein Aufrufer, eine Regel steckt in Daten, ein nächtlicher Job nutzt einen anderen Einstiegspunkt, oder eine betriebliche Abhängigkeit taucht in der geprüften Datei überhaupt nicht auf.
Deshalb entscheiden Kontextgrenzen darüber, ob agentengestützte Programmierung bei Legacy-Software funktioniert. Die sinnvolle Arbeitseinheit ist das Verhalten, das Programme, Skripte, Datenbankobjekte, Zeitpläne, Dateien und Betriebsabläufe durchquert. Eine Datei ist nur einer der Orte, an denen ein Teil dieses Verhaltens aufgeschrieben wurde.
Ich habe saubere Patches durch Reviews gehen sehen, weil jede sichtbare Zeile schlüssig war. Der Fehler kam später, als eine Steuerdatei einen alten Modus auswählte, ein dynamisch benanntes Programm einen Parameter an einer nirgends dokumentierten Position erhielt oder ein erneut gestarteter Batch Datensätze vorfand, die der Online-Pfad nie erzeugt. Sorgfältigeres Bearbeiten einzelner Zeilen löst diese Fehlerklasse nicht. Der Agent muss zuerst das System rund um die Zeile entdecken.
Eine Datei ist keine Verhaltenseinheit
Legacy-Verhalten passt selten in die Datei, die scheinbar dafür zuständig ist. Ein COBOL-Programm berechnet vielleicht einen Betrag, doch JCL wählt den Eingabedatensatz, ein SORT-Schritt ändert die Reihenfolge der Sätze, ein Copybook legt Feldpositionen fest und ein späteres Programm deutet das ausgegebene Statusbyte. Wer nur die Berechnung liest, erhält eine schlüssige, aber unvollständige Geschichte.
Dasselbe Muster gibt es außerhalb von Mainframes. Ein VB6-Formular ruft eine COM-Komponente auf, deren Registrierung eine Version auswählt. Ein PHP-Controller bindet eine Konfigurationsdatei ein, die Bereitstellungsskripte zusammensetzen. Ein RPG-Programm liest einen Datenbereich und ruft ein weiteres Programm über einen Namen auf, der in einem Feld steht. Ein PL/SQL-Paket verlässt sich auf einen Trigger, der die Zeile nach dem Schreiben verändert. Keine dieser Abhängigkeiten muss wie ein normaler Import aussehen.
Diese Unterscheidung zählt: Nähe im Quelltext bedeutet keine Zuständigkeit für Verhalten. Zwei Funktionen in derselben Datei können zur Laufzeit nichts miteinander zu tun haben, während ein JCL-Member und ein COBOL-Absatz in verschiedenen Bibliotheken gemeinsam einen unteilbaren Produktionsvorgang bilden. Gewichtet ein Agent Kontext hauptsächlich nach Verzeichnisabstand, Importanweisungen oder passenden Bezeichnern, übersieht er Abhängigkeiten, die für den Betrieb selbstverständlich sind.
Vor einer Dateiänderung muss klar sein, was dieses Verhalten auslöst, welche Eingaben seine Zweige wählen, welchen dauerhaften Zustand es liest oder schreibt und wer das Ergebnis verbraucht. Aus diesen Fragen entsteht eine Systemgrenze. Sie kann zwölf Dateien oder zwölftausend umfassen. Ihre Größe folgt dem Verhalten, nicht dem geöffneten Editor-Tab.
Die praktische Folge ist eindeutig. Ein Werkzeug, das Repository, Builddefinitionen, Jobsteuerung, Schemas und Tests nicht übergreifend durchsuchen und verstehen kann, sollte keine autonome Legacy-Änderung vornehmen. Es kann einen Absatz erklären oder einen Unit-Test entwerfen. Die Auswirkungen einer Produktionsänderung kann es nicht feststellen.
Aufrufstellen liegen außerhalb des Importgraphen
Ein aus expliziten Funktionsaufrufen gebauter Aufrufgraph ist nützlich, aber kein Aufrufgraph des Systems. Legacy-Systeme wählen Arbeit über Zeichenketten, Tabellen, Scheduler, erzeugten Quelltext, Bindeschritte, Befehlsdateien und Konventionen aus. Oft ist genau die fehlende Kante entscheidend.
Die ILE-Dokumentation von IBM liefert ein klares Beispiel. Eine IBM-i-Anwendung kann statische Prozeduraufrufe verwenden, die beim Binden des Programms aufgelöst werden, oder dynamische Programmaufrufe, deren Zielname erst zur Laufzeit feststeht. Eine reine Quelltextsuche findet die statische Referenz häufig. Ein dynamischer Aufruf über einen Bezeichner kann von einem Wert abhängen, der aus einer Datei, Nachricht, einem Datenbereich oder Parameter stammt. Die Suche nach dem Namen des aufgerufenen Programms findet keinen Wert, den die Produktion erst später zusammensetzt.
Dieselbe blinde Stelle begegnet uns in alltäglichen Varianten:
- Ein Scheduler startet ein Shell-Skript, das ein Programm unter einem Alias ausführt.
- Eine Datenbanktabelle ordnet Transaktionscodes den Namen von Handlern zu.
- Reflection lädt eine Klasse, deren Name in der Konfiguration steht.
- Ein Tabellenmakro ruft über ein spät gebundenes Objekt eine COM-Methode auf.
- Erzeugte JCL setzt einen Prozedurnamen erst nach symbolischer Ersetzung ein.
In der Praxis werden statische Erreichbarkeit und Laufzeitabhängigkeit oft vermischt. Statische Erreichbarkeit fragt, ob Quelltext oder kompilierte Metadaten einen Pfad erkennen lassen. Laufzeitabhängigkeit fragt, ob die Produktion unter irgendeinem Zustand Daten oder Steuerung über diesen Pfad leiten kann. Wer die erste Frage als Beweis für die zweite nimmt, bekommt ein ansprechendes, aber unvollständiges Diagramm.
Ein Agent braucht Belege für beides. Er sollte explizite Referenzen extrahieren und danach Zeichenkettenliterale, Konfigurationsschlüssel, Jobschritte, Bindemetadaten, Dispatch-Tabellen in Datenbanken und Produktionstraces prüfen. Kann er ein dynamisches Ziel nicht auflösen, muss er eine offene Kante mit dem Ausdruck und seinen möglichen Quellen festhalten. Schweigen ist keine gültige Auflösung.
Schon eine einfache Repository-Suche zeigt, wie schnell ein angeblich isoliertes Symbol sein Modul verlässt:
rg -n -uu 'CALC-TAX|CALCTAX|calc_tax' .
rg -n -uu 'EXEC PGM=|CALL +[A-Z0-9-]+|CALLP|PROCEDURE DIVISION' .
rg -n -uu 'handler|program_name|transaction_code' config db jobs src
Eine echte Ausgabe enthält Pfade und Zeilennummern, etwa jobs/NIGHTTAX.jcl:18://STEP20 EXEC PGM=CALCTAX. Das Artefakt ist nicht ausgefeilt, zwingt einen Reviewer aber dazu, Aufrufer jenseits der geöffneten Datei zu prüfen. Ein ernstzunehmender Agent sollte automatisch eine reichhaltigere Fassung dieser Karte aufbauen und die Belege für jede Kante aufbewahren.
Geschäftsregeln wandern durch Daten
Viele Legacy-Regeln sind Werte, Layouts und Abläufe statt benannter Funktionen. Ein Agent kann jede sichtbare Bedingung bewahren und das Ergebnis trotzdem verändern, wenn er ein gepacktes Dezimalfeld, ein Sentinel-Datum, einen Satztyp, eine Sortierfolge oder die Bedeutung eines Leerzeichens missversteht.
Nehmen wir ein nächtliches Gebührenprogramm. Im Code steht, dass die Kontoklasse P eine Befreiung erhält. Die Klasse kommt nicht direkt aus dem Kontodatensatz. Ein früherer Extrakt ordnet Produktcodes über eine Steuertabelle zu, schreibt eine Ein-Byte-Klasse an Position 47 und sortiert Ausnahmen vor normale Datensätze. Vor dem Monatsabschluss ersetzt der Betrieb diese Tabelle. Die Regel, die laut Reviewer in einer einzelnen IF-Anweisung steckt, verteilt sich tatsächlich auf Tabelle, Dateilayout, Sortiervertrag und Betriebsablauf.
An dieser Stelle liefern dateibezogene Agenten plausible Transliterationen. Sie wandeln das IF korrekt um, definieren ein hübsches Enum und lesen eine CSV-Datei in einen modernen Dienst ein. Dann entfernen sie Leerraum oder interpretieren ein leeres Feld als null. Das ursprüngliche Programm verglich ein Leerzeichen mit fester Breite, weshalb einige Konten nun in einem anderen Zweig landen. Aus der umgeschriebenen Funktion abgeleitete Unit-Tests bestehen alle, weil sie die neue Deutung wiederholen.
Ein Systeminventar muss deshalb Datensemantik enthalten, nicht nur Schemanamen. Für jeden Grenzdatensatz und jede Tabelle sind Feldpositionen, Kodierungen, Standardwerte, Nullverhalten, Vorzeichenformate, Rundung, Reihenfolge, Behandlung von Duplikaten und Regeln für ungültige Sätze zu erfassen. Ändert sich ein Steuerwert außerhalb der Versionsverwaltung, muss dokumentiert werden, wie er ausgerollt wird und welcher Job ihn liest.
Eine moderne Datenart ist nicht automatisch richtiger als die alte Darstellung. Die Umwandlung von 9(7)V99 COMP-3 in einen Dezimaltyp kann sinnvoll sein, aber erst nachdem Skalierung, Vorzeichen, Rundung, Überlauf und der Umgang mit fehlerhaften Eingaben erhalten bleiben. Wer ein sechs Zeichen langes Datum durch einen Zeitstempel ersetzt, kann das Zieldesign eindeutiger machen und dabei unbemerkt eine Jahrhundertregel erfinden, die das Quellsystem nie hatte.
Der Agent muss auch Schreiber mit Lesern verbinden. Ein Feld, das im Erzeuger ungenutzt aussieht, kann Positionsfüllung sein, die ein Verbraucher drei Schritte später benötigt. Wird es gelöscht, verschieben sich alle nachfolgenden Felder, ohne dass ein Compilerfehler entsteht. Eine solche Beziehung wird am sichersten durch einen ausdrücklichen Vertrag mit Beispielbytes und geparsten Werten beschrieben, nicht durch den Prosahinweis, die Dateien seien kompatibel.
Der nächtliche Batch ist eine andere Anwendung
Ein Online-Pfad und ein Batch-Pfad, die Code teilen, sind dennoch verschiedene Anwendungen, wenn sie unter anderen Eingaben, Identitäten, Zeitbedingungen und Wiederherstellungsregeln laufen. Ein bestandener interaktiver Test sagt wenig über einen Job aus, der nach Mitternacht angesammelten Zustand verarbeitet.
Die z/OS-Dokumentation von IBM beschreibt JCL als die Stelle, an der das System erfährt, wo Eingaben liegen, wie sie zu verarbeiten sind und was mit den Ausgaben geschieht. DD-Anweisungen verbinden die Namen, die ein Programm verwendet, mit tatsächlichen Datensätzen und geben Einzelheiten wie Disposition und Satzformat an. Das ist keine Verpackung um die Anwendung. Es ist ausführbarer Kontext.
Stellen wir uns eine Änderung vor, die einer Online-Bestellfunktion einen neuen Status hinzufügt. Der Anfragepfad schreibt H für zurückgestellte Bestellungen, zeigt die richtige Meldung an und besteht das Review. Der nächtliche Abrechnungsjob liest dieselbe Datei. Sein erster Schritt sortiert nur ältere Statuswerte in die Abrechnungseingabe, während ein Fehlerschritt alle anderen in einen temporären Datensatz mit DISP=(NEW,PASS) kopiert. Ein späterer Schritt läuft nur, wenn eine Rückgabecode-Bedingung zutrifft. Der neue Status überspringt die Abrechnung, landet in der temporären Datei und verschwindet, sobald der Job normal endet. Keine Quelldatei des geprüften Dienstes zeigt dieses Ergebnis.
Der Fehler wartet vielleicht auf Datenmenge oder Kalenderzustand. Ein Test am Tag verwendet einen Datensatz und eine saubere Datenbank. Der Batch trifft auf Duplikate aus mehreren Wiederholungen, schließt vor der Verarbeitung ein Buchungsdatum und führt nach einigen Tausend Datensätzen einen Commit aus. Ein Neustart setzt nach dem letzten Prüfpunkt ein, nicht nach der Transaktion, die der Test erwartet hat. Korrektheit umfasst das Neustartverhalten, denn der Betrieb wird einen teilweise abgeschlossenen Job irgendwann erneut ausführen.
Für jeden geplanten Ablauf sollte der Agent fünf Tatsachen modellieren:
- Auslöser, Kalender, Identität und Umgebung.
- Die geordneten Schritte und Bedingungen, durch die sie übersprungen oder wiederholt werden.
- Konkrete Ein- und Ausgaben einschließlich temporärer Datensätze.
- Verhalten bei Commit, Prüfpunkt, Wiederholung und erneutem Lauf.
- Den Beleg, anhand dessen der Betrieb den Erfolg feststellt.
Ein grüner Prozess-Exitcode muss nicht das Erfolgskriterium sein. Manche Unternehmen akzeptieren definierte Warncodes, prüfen Datensatzanzahlen oder gleichen eine Kontrollsumme in einem späteren Bericht ab. Ein Agent, der nur Quelltext und Unit-Tests sieht, optimiert auf das falsche Signal.
Konfiguration führt Richtlinien aus
Konfiguration verdient dieselbe Prüfung wie Quelltext, denn sie wählt Verhalten aus, liefert Geschäftswerte und verbindet Komponenten zur Laufzeit. Wer sie als "bloße Konfiguration" bezeichnet, genehmigt leicht eine Änderung, ohne die tatsächlich ausgeführte Regel zu prüfen.
Legacy-Konfiguration liegt selten in einem ordentlichen Verzeichnis. Sie kann ein symbolischer JCL-Parameter, ein IBM-i-Datenbereich, eine INI-Datei neben einer Desktop-Anwendung, eine über ein Access-Formular gepflegte Zeile, ein Registrierungswert, ein Umgebungs-Member oder eine in einen überwachten Ordner kopierte Tabelle sein. Manche Werte stehen unter Versionskontrolle. Andere kommen über Bereitstellungswerkzeuge oder einen Betriebsablauf. Der Agent muss beide Arten finden und unterscheiden.
Angenommen, ein Schadenprogramm wählt eine Preisroutine aus einer Tabelle. Der Quelltext enthält einen harmlosen Standardwert, also schreibt und testet der Agent diesen Zweig neu. In der Produktion gibt es regionsbezogene Zeilen, die vier ältere Routinen benennen. Eine davon erwartet ein zusätzliches Argument in einem gemeinsam genutzten Puffer. Der neue Dienst startet fehlerfrei und verarbeitet die Standardtests. Beim ersten Schaden aus dieser Region ruft er keinen Handler auf oder übergibt dem neuen Handler einen unvollständigen Vertrag. Die fehlende Aufrufstelle war eine Tabellenzeile, keine Codezeile.
Konfigurationswerte sind nach ihrer Wirkung zu behandeln. Ein Wert, der nur die Ausführlichkeit der Protokollierung ändert, birgt wenig Verhaltensrisiko. Ein Wert, der ein Programm auswählt, einen Schwellenwert ändert, Rundung steuert, Zugriff gewährt, eine Dateilayoutversion festlegt oder die Commit-Häufigkeit verändert, gehört in die Auswirkungskarte. Die Unterscheidung folgt der Konsequenz, nicht der Dateiendung.
Für jeden Wert, der Verhalten auswählt, sollte der Agent vier Fragen beantworten:
- Wo wird der Wert definiert und wer darf ihn ändern?
- Welcher Code liest ihn, und wann geschieht das?
- Welche Werte kamen in echten Umgebungen vor?
- Was passiert, wenn der Wert leer, veraltet, unbekannt oder nicht verfügbar ist?
Standardwerte verdienen besonderes Misstrauen. Ein Fallback, der einen Unit-Test bequem macht, kann in der Produktion das fehlgeschlagene Laden einer Konfiguration verdecken. Das Quellsystem stoppt vielleicht bei einem fehlenden Steuer-Member, während die Neufassung still einen Standard auswählt. Beide Implementierungen erzeugen für konfigurierte Fälle gültige Ergebnisse, aber ihre Fehlerverträge unterscheiden sich. Paritätstests müssen fehlende und fehlerhafte Konfiguration einbeziehen, nicht nur erwartete Werte.
Zusammen mit der für die Analyse verwendeten Quellrevision sollte ein Bereitstellungsschnappschuss erfasst werden. Scheduler-Export, Steuertabellen, Schema und Umgebungsdateien sollten nach Möglichkeit einen Hash oder eine Version erhalten. Kann ein Reviewer nicht erkennen, welche Konfiguration der Agent vorausgesetzt hat, ist die Aussage zu den Auswirkungen nicht reproduzierbar. Auch ein vollständiger Codeindex mit unbekannter Produktionskonfiguration liefert nur Teilkontext, und der Agent muss das klar sagen.
Vor dem Patch entsteht die Karte
Bevor der Agent Code vorschlägt, sollte er eine belegte Auswirkungskarte erstellen. Sie ist kein Architekturposter, sondern eine Arbeitsmenge aus Knoten und Kanten, die mit Dateien, Definitionen, Laufzeitbeobachtungen und offenen Fragen verknüpft sind.
Am Anfang stehen Einstiegspunkte: Online-Routen, Nachrichtenempfänger, geplante Jobs, Befehlsprogramme, gespeicherte Prozeduren, Desktop-Ereignisse und Bedienerkommandos. Danach folgen Programmaufrufe, Dateioperationen, Tabellenzugriffe, erzeugte Artefakte, Konfigurationsauswahl und Deployment-Bindungen. Kanten werden als statisch, konfiguriert, beobachtet oder abgeleitet markiert. Diese Kennzeichnung verhindert, dass eine Vermutung den Rang einer Tatsache erhält.
Für jede vorgeschlagene Änderung nutze ich einen kompakten Änderungsdatensatz:
{
"change": "add held order status H",
"entry_points": ["POST /orders/{id}/hold", "NIGHTSET STEP20"],
"writers": ["OrderStatus.bas", "HOLDORDR.cbl"],
"readers": ["SETTLE.cbl", "RECON.sql"],
"contracts": ["ORDER-REC copybook", "status_control table"],
"unresolved": ["Does restart input retain H records?"],
"required_evidence": ["online trace", "nightly replay", "reconciliation totals"]
}
Dieses Objekt soll unbequem sein. Es macht den zweiten Einstiegspunkt und die offene Neustartfrage sichtbar, bevor jemand den Patch genehmigt. Auf die genauen Feldnamen kommt es nicht an. Entscheidend ist, dass der Agent betroffene Einstiegspunkte, Leser, Verträge und fehlende Belege nennen muss.
Die beliebte Alternative heißt schrittweise Offenlegung: Man gibt dem Agenten die Zieldatei, lässt ihn verwandte Dateien anfordern und stoppt, sobald er genug zu haben meint. Das spart Tokens und wirkt in einer Demo effizient. Für die Auswirkungsanalyse ist es falsch, weil die erste Datei jede spätere Anfrage prägt. Enthält sie keinen Hinweis auf Scheduler, Steuertabelle oder erzeugte Prozedur, fragt der Agent nie danach.
Schrittweise Offenlegung ist nach der Entdeckung nützlich, wenn der Agent detaillierten Text für einen bekannten Kartenausschnitt braucht. Die Entdeckung selbst verlangt eine repositoryweite Indizierung und sprachenübergreifende Analyse. Der Agent darf seine Schlussfolgerungen fokussieren, doch der Suchraum darf nicht an der Dateigrenze beginnen.
Die Karte bietet Menschen außerdem eine bessere Review-Fläche. Ein Reviewer kann eine fehlende Kante beanstanden, Belege für eine Ableitung verlangen oder einen Betriebsablauf hinzufügen, der nicht im Repository steht. Wer nur den fertigen Diff prüft, muss diese Karte im Kopf rekonstruieren. Genau bei dieser Arbeit sollte der Agent helfen.
Kontext braucht Schichten statt eines riesigen Prompts
Gesamtsystemkontext bedeutet nicht, eine Million Zeilen in einen Prompt zu kopieren. Der Agent muss das vollständige System über Darstellungen abrufen und verstehen können, die zur jeweiligen Frage passen, und zugleich den Weg zurück zu den Quellbelegen bewahren.
Eine Schicht enthält das Inventar: Sprachen, Build-Einheiten, Schemas, Jobs, Einstiegspunkte, Dateien, Prozeduren und Konfigurationsquellen. Eine weitere erfasst Beziehungen wie Aufrufe, Lese- und Schreibzugriffe, Zeitpläne, Includes, Bindungen und Erzeugungsschritte. Eine semantische Schicht hält Verträge und wahrscheinliche Zuständigkeiten fest. Laufzeitbelege ergänzen Traces, produktionsnahe Beispiele, Jobprotokolle und beobachtete Dispatch-Ziele.
Diese Schichten beantworten unterschiedliche Fragen. Für die Umbenennung eines Feldes braucht der Agent Layoutdefinitionen und jeden Leser. Für eine Berechnungsänderung braucht er Aufrufer, Datenherkunft, Rundungsregeln und Vergleichsausgaben. Zum Aufteilen eines Batchjobs braucht er Schrittbedingungen, Lebenszeiten temporärer Ressourcen, Prüfpunktverhalten und betriebliche Wiederherstellung. Keine feste Chunking-Strategie beantwortet alle drei Fragen.
Zusammenfassungen helfen, sind aber verlustbehaftete Zwischenspeicher. Sie können sagen, dass ein Programm Gebühren berechnet, und dabei den Zweig auslassen, der nur für stornierte Transaktionen während des Abschlusses gilt. Jede zusammengefasste Aussage sollte Verweise auf konkrete Quellabschnitte oder Laufzeitdatensätze behalten. Berührt eine Änderung diese Aussage, muss der Agent die Quellen erneut öffnen, statt allein aus der Zusammenfassung zu folgern.
Auch die Aktualität des Kontexts zählt. Erzeugte Copybooks, Datenbankdefinitionen, Scheduler-Exporte und bereitgestellte Konfiguration können vom Haupt-Repository abweichen. Der Agent sollte zeigen, welchen Stand er analysiert hat. Eine aktuelle COBOL-Datei mit dem JCL-Export des letzten Quartals zu mischen, erzeugt ein künstliches System, das nirgends gelaufen ist.
Repository-Analyse kann außerdem nicht alles wissen. Ein Operator ändert vielleicht während eines Vorfalls ein Steuer-Member. Ein Partner sendet undokumentierte Satzvarianten. Eine Desktop-Anwendung hängt möglicherweise von der Registrierung eines Rechners ab. Die richtige Reaktion besteht darin, die Lücke zu benennen und Laufzeitbelege zu verlangen, statt sie mit einer selbstsicheren Annahme zu füllen.
Dieser Schichtenansatz hält die Kosten im Griff, ohne den Umfang zu opfern. Breite Indizes ermitteln Kandidaten günstig. Gezielter Abruf liefert den genauen Quelltext, wenn der Agent über eine Kante nachdenkt. Laufzeit-Replays prüfen das entstehende Verhalten. Das System bleibt für den Agenten erreichbar, obwohl nicht jedes Token gleichzeitig aktiv ist.
Parität wird an der Verhaltensgrenze geprüft
Tests, die nur gegen die neue Implementierung geschrieben wurden, beweisen interne Konsistenz, nicht die Erhaltung des Verhaltens. Eine Neufassung kann eine vollständige neue Unit-Test-Suite bestehen und bei genau den Fällen von der Produktion abweichen, die sie missverstanden hat.
Das stärkste praktische Orakel ist das Altsystem selbst. Repräsentative Eingaben werden an seinen echten Grenzen erfasst, durch beide Implementierungen geschickt und nur bei absichtlich nicht deterministischen Werten normalisiert. Danach vergleicht man beobachtbare Ausgaben. Dazu können Antwortinhalte, Datenbankänderungen, erzeugte Dateien, Nachrichten, Rückgabecodes, Kontrollsummen und Protokolle gehören, die der Betrieb als Vertrag behandelt.
Ein Paritätsfall muss genügend Einzelheiten enthalten, um eine Abweichung zu reproduzieren:
{
"case_id": "nightly-held-order-restart",
"entry_point": "NIGHTSET",
"input_refs": ["orders.dat#sha256:...", "status_control#2026-08-01"],
"source": {"rc": 4, "settled": 812, "held": 17, "control_total": "194033.22"},
"target": {"rc": 0, "settled": 829, "held": 0, "control_total": "196801.04"},
"comparison": "mismatch"
}
Das Beispiel zeigt, warum passende Exitcodes ein schwacher Beleg sind. Das Quellsystem akzeptiert Rückgabecode 4 und bewahrt zurückgestellte Datensätze. Das Ziel gibt null zurück, nachdem es sie abgerechnet hat. Eine gewöhnliche Zustandsprüfung bevorzugt das falsche Ergebnis.
Aufgezeichneter Verkehr verlangt Disziplin. Sensible Werte müssen entfernt oder geschützt, verhaltensrelevante Reihenfolgen erhalten und Fehler sowie Wiederholungen einbezogen werden, statt nur erfolgreiche Anfragen zu betrachten. Batch-Fixtures brauchen produktionsnahe Mengenkategorien, Grenzdaten, Duplikate, fehlerhafte Datensätze und Neustartpunkte. Nicht jeder Produktionsdatensatz ist nötig, wohl aber jede bekannte Verhaltensklasse.
Parität verbietet keine Architekturänderung. Sie trennt beabsichtigte von unbeabsichtigten Änderungen. Sequenzielle Dateiverarbeitung kann durch Datenbanktransaktionen ersetzt, ein Monolith in Dienste geteilt oder ein numerischer Kern nach Rust verschoben werden. Der Vergleich zeigt, wo sich sichtbares Verhalten bewegt hat. Ein Mensch kann einen beabsichtigten Unterschied dann mit Begründung genehmigen, statt ihn erst in der Abstimmung zu finden.
CodeHero nutzt diese Grenze bewusst: Die Plattform liest den gesamten Codebestand sprachenübergreifend und prüft das neu geschriebene System danach mit einem Paritätssystem gegen aufgezeichneten Produktionsverkehr. Dieser Mechanismus zählt mehr als die Frage, ob erzeugter Code in einem Pull Request idiomatisch aussieht.
Geprüft wird die Auswirkungsaussage, nicht nur der Diff
Ein agentengestütztes Review sollte die Aussage des Agenten zu den Systemauswirkungen bewerten. Der Diff bleibt notwendig, ist aber das letzte Artefakt einer Kette, die mit Entdeckung beginnt und mit Verhaltensbelegen endet.
Ein brauchbares Review-Paket enthält das gewünschte Verhalten, betroffene Einstiegspunkte, veränderte Verträge, gefundene Verbraucher, offene Kanten, Testbelege und akzeptierte Unterschiede. Jede Aussage muss nachvollziehbar bleiben. Behauptet der Agent, ein Feld habe genau einen Leser, sollte der Reviewer die Suche oder den Trace öffnen können, der diese Anzahl stützt.
Damit ändert sich das Genehmigungsgespräch. Statt zu fragen, ob die neue Funktion vernünftig aussieht, fragt der Reviewer, warum RECON.sql nicht betroffen ist, ob der nächtliche Neustart wiederholt wurde und welcher Beleg leere Statuswerte abdeckt. Solche Fragen kann ein Agent schwerer vortäuschen, während erfahrene Entwickler sie entschieden beantworten können.
Drei Warnzeichen verdienen Aufmerksamkeit. Erstens beschreibt der Agent Abhängigkeiten, ohne beobachtete Tatsachen von Ableitungen zu trennen. Zweitens stammen seine Tests vollständig aus dem neuen Entwurf statt aus erfasstem Legacy-Verhalten. Drittens verwendet er Aussagen wie "alle Aufrufer", ohne die Suchgrenze offenzulegen. Jedes Zeichen bedeutet, dass die Kontextbehauptung stärker als der Beleg ist.
Reviewer brauchen auch eine Stopregel. Eine Änderung ist zu blockieren, wenn eine offene Kante Geld, Berechtigungen, regulierte Datensätze, unumkehrbare Ausgaben oder Wiederherstellungsverhalten ändern kann. Bei einem harmlosen Darstellungsfehler kann eine begrenzte Ableitung genügen. Kontextvollständigkeit ist nicht binär. Die erforderliche Belegstärke steigt mit den Folgen eines Fehlers.
Bewerten Sie einen Agenten nicht nach akzeptierten Zeilen oder Pull-Request-Geschwindigkeit. Solche Kennzahlen belohnen lokale Plausibilität. Prüfen Sie, wie oft Auswirkungsprognosen mit beobachteten Folgen übereinstimmen, wie viele Paritätsabweichungen entkommen und ob erneute Läufe sowie betriebliche Kontrollen erwartungsgemäß funktionieren. Auch ohne formale Punktzahl trennen diese Fragen Schreibhilfe von Entwicklungsarbeit.
Gesamtsystemumfang verändert die Wirtschaftlichkeit
Repositoryweite Entdeckung kostet vor der ersten Bearbeitung mehr. Genau deshalb spart sie bei Legacy-Arbeit Zeit. Die teuren Fehler treten auf, nachdem eine billige lokale Änderung eine unsichtbare Grenze überschritten hat: beim Abschluss, in einem Batchfenster, bei der Abstimmung oder nachdem die einzige Person mit Kenntnis der Neustartfolge gegangen ist.
Die Kosten bestehen nicht nur aus Reparatur. Eine schlechte Modernisierung lehrt das Unternehmen, dem Zielsystem zu misstrauen. Teams lassen die Legacy-Anwendung als Schatten weiterlaufen, vergleichen Ergebnisse manuell und verweigern spätere Änderungen. Die nominelle Neufassung ist fertig, während die betriebliche Migration nie abgeschlossen wird.
Gesamtsystemanalyse verhindert noch eine subtilere Verschwendung: veraltete Architektur zu transliterieren, weil der Agent ihren Zweck nicht erkennt. Sieht er nur ein Programm, scheint die sicherste Lösung darin zu bestehen, seine Absätze in einer neuen Sprache nachzubauen. Sieht er Aufrufer, Datenverträge, Jobfluss und Verhalten an der Grenze, kann er die geforderten Ergebnisse bewahren und zufällige Strukturen ersetzen.
Diesen Maßstab legen wir an, wenn CodeHero Legacy-Systeme in unter 30 Tagen in Go, Rust, TypeScript und Postgres neu schreibt. Der kurze Zeitplan ist nur glaubwürdig, wenn Entdeckung, sprachenübergreifende Analyse und Paritätsprüfung das System als Ganzes behandeln, statt darauf zu warten, dass Menschen einzelne Dateien zufüttern.
Ein KI-Agent braucht kein mystisches Verständnis jeder historischen Entscheidung. Er braucht eine ehrliche Grenze, Belege für die Kanten darin und Tests an den Stellen, an denen Verhalten die Grenze verlässt. Kann Ihr Programmieragent nicht sagen, welcher nächtliche Job den Datensatz liest, den er ändern will, hat er sich das Recht auf diese Änderung nicht verdient.
FAQ
Warum ist dateibezogener Kontext bei Legacy-Code riskant?
Legacy-Verhalten durchquert oft Quelldateien, Jobdefinitionen, Schemas, Steuertabellen und Betriebsabläufe. Dateibezogener Kontext verbirgt diese Kanten, sodass ein Agent plausiblen Code erzeugen und das System an anderer Stelle verändern kann.
Bedeutet vollständiger Codekontext, jede Datei in einen Prompt zu setzen?
Nein. Das vollständige System wird indiziert, danach werden für jede Frage die passenden Quellen, Beziehungen, Verträge und Laufzeitbelege abgerufen. Jede Zusammenfassung sollte weiterhin auf konkrete Belege verweisen.
Findet ein statischer Aufrufgraph jede Legacy-Abhängigkeit?
Nein. Dynamische Programmnamen, Scheduler-Einträge, Dispatch-Tabellen, erzeugte Artefakte und Deployment-Bindungen können Laufzeitkanten bilden. Offene dynamische Kanten müssen sichtbar bleiben, bis Traces oder Konfiguration sie auflösen.
Warum scheitern KI-Änderungen in nächtlichen Batchjobs?
Batchjobs haben andere Einstiegspunkte, angesammelte Eingaben, Identitäten, Schrittbedingungen und Neustartregeln. Ein Online-Test deckt diese Kombination selten ab, selbst wenn beide Pfade Geschäftslogik teilen.
Was sollte ein KI-Agent vor der Änderung eines Legacy-Programms prüfen?
Er sollte Einstiegspunkte, Aufrufer, Leser und Schreiber, Datenverträge, geplante Abläufe, Konfiguration, Wiederherstellung und sichtbare Ausgaben ermitteln. Außerdem muss er sagen, welche Abhängigkeiten nur abgeleitet oder noch offen sind.
Wie testet man eine KI-erzeugte Legacy-Neufassung?
Repräsentative, produktionsnahe Eingaben laufen durch Quelle und Ziel, danach werden alle sichtbaren Wirkungen verglichen. Dazu gehören je nach System Datenbankänderungen, Dateien, Nachrichten, Rückgabecodes, Kontrollsummen, Fehler und Neustartfälle.
Ist Verhaltensparität dasselbe wie das Kopieren der alten Architektur?
Nein. Parität bewahrt genehmigtes sichtbares Verhalten und lässt die interne Gestaltung offen. Bei einer Abweichung macht das Testsystem den Unterschied sichtbar, damit ein Mensch ihn genehmigen oder ablehnen kann.
Welche Belege sollten einen vom Agenten erzeugten Patch begleiten?
Verlangen Sie eine Auswirkungskarte, betroffene Einstiegspunkte, veränderte Verträge, gefundene Verbraucher, offene Kanten und Testergebnisse. Aussagen wie "alle Aufrufer" sollten den zugrunde liegenden Suchraum offenlegen.
Wann sollte ein Reviewer eine KI-erzeugte Legacy-Änderung blockieren?
Blockieren Sie sie, wenn eine offene Abhängigkeit Geld, Zugriff, regulierte Datensätze, unumkehrbare Ausgaben oder Wiederherstellung verändern kann. Bei geringerem Risiko ist begrenzte Unsicherheit vertretbar, aber der Agent muss sie klar benennen.
Kann KI ein Legacy-System mit einer Million Zeilen modernisieren?
Die Größe allein entscheidet das nicht. Der Agent braucht repositoryweite Entdeckung, sprachenübergreifende Abhängigkeitsanalyse, kontrollierten Abruf und Paritätsbelege. Sonst schafft ein größeres System nur mehr Orte für verborgenes Verhalten.