FAQ

Warum installiert die Suite so viel Tooling, statt einfach mit dem Refactoring loszulegen?

Weil man einem LLM nicht zutrauen kann, allein und sicher weitreichende Codeänderungen vorzunehmen. Der Tooling-Baum führt deterministische Checks und Sicherungen ein – statische Analyse, Coding-Standards, einen funktionierenden Testrunner –, bevor ein Agent den Code anfassen darf. So wird eine falsche oder übermütige Änderung mechanisch abgefangen, statt sich darauf zu verlassen, dass der Agent seinen eigenen Fehler bemerkt.

Fast alles davon lässt sich ablehnen, aber auf Kosten von Codequalität und Abwärtskompatibilität: weniger Gates heißt weniger, was eine schlechte Änderung vor dem Merge aufhält. Und nichts zwingt dir die Reihenfolge auf: Nenne im Aufruf den Track, den du willst.

Warum fragt mich die Suite bei jedem Schritt?

Weil alles, was sie tut, an einem Ort landet, den andere sehen: ein Ticket in deinem Tracker, ein Branch, ein Merge Request. Standardmäßig wird nichts geschrieben, was du nicht bestätigt hast, und jede Frage kommt mit einer Empfehlung, sodass „ja“ weiterführt.

Willst du lieber nicht gefragt werden, sag es im Aufruf („mach das selbst“) oder mitten im Run („mach ab hier selbst weiter“). Die Suite nimmt dann an jedem Punkt ihre eigene Empfehlung. Es ist in beiden Fällen dieselbe Kette von Entscheidungen, ein autonomer Run tut also nichts, was ein interaktiver Run nicht empfohlen hätte.

Warum ist „autonom“ keine Einstellung, die ich einmal setze?

Eine einmal gesetzte Einstellung ist die, die man vergisst. Frühere Versionen hatten zwei solche Einstellungen pro Maschine, und ein Entwickler konnte nicht bei einem Aufruf „zeig mir, was du tun würdest“ und beim nächsten „mach es“ sagen. Jetzt sagt es der Aufruf. Für einen geplanten Job ist das eine Formulierung mehr im Befehl.

Was passiert, wenn ich einen Run starte und weggehe?

Ohne den Hinweis auf Autonomie endet der Run an seinem ersten Entscheidungspunkt. Was du hinterher vorfindest, ist dieser Entscheidungspunkt als Bericht – was er gefunden hat, die Optionen, was er empfiehlt –, und nichts wurde geschrieben. Das ist Absicht: Ein Aufruf, den niemand begleitet, soll dich nicht überraschen.

Warum hält die Suite keinen eigenen Zustand?

Früher tat sie das: ein Dokument, das festhielt, welche Tools offen waren, wann jeder Track zuletzt lief, was abgelehnt war und welcher Merge Request zu welchem Ticket gehörte. Dieser Datensatz verdoppelte, was dein Tracker und deine Forge schon zeigen, veraltete, sobald du außerhalb der Suite gearbeitet hast, und brauchte mehr Regeln als alles andere zusammen.

Jetzt sind deine offenen Tickets die Arbeitsliste, und der Rest wird jedes Mal per Suche gefunden. Schließt du ein Ticket von Hand, mergst selbst etwas oder richtest ein Tool eigenständig ein, findet der nächste Run das so vor. Es gibt nichts zu synchronisieren, nichts auf eine andere Maschine mitzunehmen, und zwei Leute können die Suite auf einem Projekt nutzen, ohne eine Datei zu teilen.

Warum werden Tickets über ihr Thema gefunden und nicht über ein Label?

Eine Markierung, die die Suite verlangt, ist eine Markierung, die du an dem Ticket vergisst, das du selbst geschrieben hast. Deshalb nennt ein Ticket, das die Suite anlegt, sein Thema in einfachen Worten – „Introduce PHPStan Level 0“ – und wird wiedergefunden, indem danach gesucht wird. Vor dem Anlegen sucht die Suite nach einem bestehenden Ticket zum Thema, offen oder geschlossen, und macht auf deinem weiter, statt ein Duplikat zu erstellen.

Ein Label hilft trotzdem: Sagt dein Tracker-Abschnitt, wie Refactoring-Tickets markiert werden, nutzt die Suite das als Hinweis, um ihre Suche einzugrenzen, und so wird ein frei geschriebenes Ticket von dir auf einem Tracker voller anderer Arbeit aufgegriffen.

Warum nur zwei Skills?

Frühere Versionen bestanden aus elf Skills, alle bis auf einen intern, jeder in dein Projekt verlinkt und unter deinen Skills aufgeführt. Die Aufteilung gab es, um jedem Schritt einen eigenen Kontext zu geben und einen Skill zum einzigen Schreiber des Zustands der Suite zu machen. Der Zustand ist weg, und ein Schritt bekommt einen eigenen Kontext, indem er zusammen mit seinen Anweisungen an einen Subagenten übergeben wird. Übrig sind die zwei Dinge, die du aufrufst: ein Run und Housekeeping allein.

Warum hat Housekeeping einen eigenen Befehl?

Damit es sich einplanen lässt. /continuous-housekeeping braucht keine Wahl zwischen Tracks: Es bearbeitet das fällige Ticket oder meldet, dass nichts fällig ist. /continuous-refactoring empfiehlt Housekeeping weiterhin, wenn sein Ticket fällig ist.

Kann ein Agent einen Run starten?

Ja, beide Befehle. Ein Agent, den du damit beauftragst, kann jeden Run an einen eigenen Subagenten übergeben, sodass jeder Run mit frischem Kontext beginnt, und den nächsten aufrufen, nachdem er sich um den Merge Request gekümmert hat. Ein solcher Run fragt niemanden, also sag „mach das selbst“ im Aufruf: Ohne das endet der Run an seinem ersten Entscheidungspunkt und schreibt nichts. Das Einzige, was er weiterhin dir überlässt, ist eine Änderung an deiner AGENTS.md. Das Driver-Playbook beschreibt einen solchen Agenten und gibt einen Prompt dafür mit.

Warum bevorzugt die Suite die eigenen Skills meines Projekts fürs Planen und Umsetzen?

Damit Refactoring-Arbeit so gebaut wird wie all deine andere Arbeit – dieselben Planungsgewohnheiten, dieselbe Testdisziplin, dasselbe Review. Die Suite schaut, was in diesem Moment verfügbar ist, und empfiehlt es; ihre eigenen Verfahren sind der Rückfall für ein Projekt, das keine hat. Die Wahl wird in jedem Run getroffen und nirgends gespeichert, ein Skill, den du morgen installierst, wird also morgen empfohlen.

Zwei Grenzen. Ein Run, den du gebeten hast, alles selbst zu machen, nutzt die eigenen Verfahren der Suite. Und ein Skill, der so markiert ist, dass nur du ihn aufrufen kannst, ist für einen Agenten unsichtbar: Willst du einen solchen nutzen, wähle am Design-Schritt „ich plane das selbst“, oder „ich setze das selbst um“, wenn der Plan vorliegt. Der Run endet dort und sagt dir, welches Ticket du deinem Skill übergeben sollst; ein späterer Run findet den Plan, den Branch oder den Merge Request und macht von dort weiter.

Wer auch immer die Änderung baut, die Suite erwartet dieselben zwei Ergebnisse – einen Plan auf dem Ticket, einen Branch mit grünen Checks – und öffnet den Merge Request selbst, sodass ein Run immer gleich endet.

Warum gibt es kein Limit für offene Merge Requests?

Frühere Versionen hörten bei zwei offenen Merge Requests und fünf offenen Kandidaten auf, Arbeit vorzuschlagen, egal was du wolltest. Wie viel parallel läuft, entscheidest du: Ein Team, das schnell reviewt, will mehr gleichzeitig in Arbeit haben als ein einzelner Maintainer. Die eine verbliebene Zahl ist eine Empfehlung, kein Limit – eine Erkundung empfiehlt, ihre drei stärksten Befunde anzulegen, und du kannst beliebig viele anlegen.

Der Preis: Nebeneinander geöffnete Merge Requests können kollidieren. Jeder startet vom Default-Branch, also lässt sich jeder für sich sauber mergen; einen Konflikt zwischen zweien aufzulösen ist deine Sache.

Warum vier Tracks, in fester Reihenfolge?

Weil die Arbeit unterschiedliche Rhythmen hat. Tooling einzurichten ist begrenzt und meist einmalig; ein strukturelles Refactoring ist offen; Wartung wiederholt sich. Eine feste Reihenfolge – Safety Net, Guardrails, Housekeeping, Investigation – über das, was gerade bearbeitbar ist, kannst du allein aus deinem Tracker vorhersagen, ohne zu wissen, wann etwas zuletzt lief.

Warum stoppt ein autonomer Run bei einem unfertigen Safety Net?

Das Safety Net fängt eine Regression ab, bevor das Urteil eines Agenten gefragt ist. Solange es unfertig ist und alle seine Tickets auf ein Review warten, liegt der sinnvolle nächste Schritt bei dir – reviewen und mergen –, nicht in mehr Arbeit auf Fundamenten, die noch nicht da sind. Deshalb sagt ein autonomer Run „Safety Net is waiting for merges“ und endet. Du kannst immer anders entscheiden: Nenne im Aufruf einen anderen Track.

Warum wird ein Track nur einmal gescannt?

Ein Scan beurteilt jedes Tool an deinem Projekt, das ist das Teuerste, was ein Run tut, und sein Ergebnis steht danach bereits in deinem Tracker: ein Ticket pro Tool, das noch einzurichten ist. Ihn in jedem Run zu wiederholen, würde Arbeit wiederholen, die die Tickets festhalten. Deshalb gilt ein Tool ohne offenes Ticket als erledigt, eine wiederkehrende Housekeeping-Aufgabe prüft das Tooling nach, und du kannst jederzeit im Aufruf um einen Scan bitten.

Warum werden manche Tools nur eingerichtet, wenn ich danach frage?

Weil ihr Wert vom Projekt abhängt, und die Suite kann ihn nicht verlässlich einschätzen. Ein Sicherheits-Scanner wie Semgrep findet viel in Code, der jahrelang ohne Guardrails gewachsen ist, und fast nichts in einem jungen Projekt, das sie von Anfang an hatte; dort ist sein Ticket nur Rauschen. Mutation Testing ist auf andere Art teuer: Es führt die Tests hunderte Male aus, was sich lohnt, sobald sie gut genug sind, um beurteilt zu werden. Ein Gate gegen committete Secrets bringt wenig zusätzlich zu Housekeeping, das die Git-Historie in jedem Zyklus scannt, mit einem eigenen Scanner, wo dein Projekt keinen hat; und eine Pipeline sieht ein Secret erst, wenn es gepusht ist, und dann muss es ohnehin rotiert werden. Ein solches Tool wird nie ungefragt angeboten und blockiert nie einen Track. Jeder Scan-Bericht nennt, was auf Anfrage verfügbar ist; nenne eines im Aufruf, und es wird vorgeschlagen und bearbeitet wie jedes andere Tool.

Warum ist das Dependency-Audit eine Housekeeping-Aufgabe und kein Tool zum Einrichten?

Weil sein Wert in der Wiederholung liegt. Ein Pipeline-Check schlägt nur bei Advisories fehl, die in dem Moment bekannt sind, in dem sich der Code ändert; ein Advisory, das nächsten Monat gegen dasselbe Lockfile veröffentlicht wird, wird nie gesehen, und Composer auditiert ohnehin bei jedem Update. Das Housekeeping-Ticket auditiert deine Abhängigkeiten in jedem Zyklus und aktualisiert, was eine gepatchte Version hat. Ein Pipeline-Job, der das Audit schon ausführt, bleibt, wie er ist.

Warum ist Housekeeping ein stehendes Ticket statt einer Stufe des Tooling-Baums?

Eine Stufe des Baums ist eine einmalige Adoption mit einem stabilen Test für „erledigt“. Wartung ist das nie. Sie braucht außerdem ein Zuhause zwischen den Zyklen: Ein Ticket, das immer offen ist, ist der Ort, an dem eine Idee, die bei der Feature-Arbeit auffällt, hinterlassen werden kann. Das Ticket nennt sein eigenes Fälligkeitsdatum, und seine letzte Aufgabe legt das nächste an, sodass sich nichts merken muss, wann Housekeeping zuletzt lief.

Warum markiert die Suite ein Ticket nach dem Plan als bereit, setzt aber nie einen Status, wenn die Arbeit beginnt?

Welchen Status ein Ticket bekommt, wenn die Arbeit beginnt, ist dein Workflow, und die Suite setzt ihn weder, noch fragt sie danach. Der Moment, in dem ihr eigener Plan auf einem Ticket landet, ist anders: Er ist für jedes Projekt derselbe, und ein Projekt, dessen Planungs-Skill nicht unbeaufsichtigt laufen kann, sähe das Ticket sonst nie markiert. Hat dein Tracker-Abschnitt einen Punkt Ready after plan, führt die Suite ihn aus, nachdem sie einen Plan gepostet hat – nicht, wenn dein eigener Skill den Plan geschrieben hat, und nicht, während eine offene Frage wartet. Ohne den Punkt wird nichts geschrieben.

Warum muss mich ein Agent fragen, bevor er eine Idee auf dem Housekeeping-Ticket hinterlässt?

Ein Kommentar in einem Tracker ist ein Schreibvorgang, um den du nicht gebeten hast. Die Zeile, die die Suite für deine AGENTS.md vorschlägt, sagt jedem Agenten, zuerst zu fragen. Aus demselben Grund wird diese Zeile selbst erst geschrieben, nachdem du zugestimmt hast – auch in einem autonomen Run.

Warum lehnt ein autonomer Run nie ein Ticket ab, das Verhalten ändern würde?

Ein Refactoring erhält, was die Anwendung tut. Stellt das Design fest, dass ein Ticket so nicht machbar ist, gibt es zwei ehrliche Antworten – als Refactoring ablehnen oder zu Feature-Arbeit machen –, und welche, ist eine Produktentscheidung. Die Suite hinterlässt den Befund als offene Frage auf dem Ticket und beendet den Run. Ablehnen ist eine Option, die du wählen kannst.

Warum schneidet ein Plan ein Ticket in mehrere Merge Requests?

Ein Merge Request ist nur so gut wie das Review, das er bekommt. Ein Tool, das zweihundert Dateien auf einmal umschreibt, ist reviewbar, wenn sich jede Datei auf dieselbe Weise ändert, und nicht reviewbar, wenn sich die Änderungen unterscheiden. Deshalb schätzt der Plan zuerst die Größe und schneidet, wo ein einzelner Merge Request zu viel wäre, an der Naht von Art oder Risiko: auf der einen Seite Umschreibungen, die den Code nur anders ausdrücken, auf der anderen Regeln, die ändern, was der Code tut. Jeder Teil steht für sich, und der Plan sagt in einem Satz, wo er schneidet und warum. Es gibt keine Dateianzahl, denn dieselbe Anzahl kann leicht oder schwer sein. Was das Ziel des Tickets nicht braucht, wird als eigenes Ticket vorgeschlagen, statt mitzulaufen.

Warum beginnt ein strukturelles Ticket mit einem Test, ein Tooling-Ticket aber nicht?

Ein Refactoring verspricht, dass sich das Verhalten nicht ändert, und das lässt sich nur gegen Verhalten prüfen, das vorher festgehalten wurde. Deshalb ist der erste Commit eines strukturellen Tickets ein Test, der festhält, was der Code heute tut, und grün ist, bevor sich irgendetwas bewegt; nachträglich geschrieben würde er den neuen Code beschreiben und nichts beweisen. Ein Typcheck oder ein Linter ist kein Ersatz. Ein Tooling- oder Baseline-Ticket lässt ein Tool den Code ändern, und deine bestehende Testsuite ist das, was einen Unterschied bemerkt, also fügt es keinen hinzu. Wo sich ein Test nicht mit vertretbarem Aufwand schreiben lässt, fragt die Suite dich, statt ungeprüft umzubauen.

Dieser erste Test deckt nur das alte Ganze ab, also bleibt er grün, wenn Code in eine neue Klasse wandert, ohne dass diese Klasse einen Test hat. Jeder neue Typ, den die Restrukturierung anlegt, bekommt deshalb einen eigenen Test, geschrieben, bevor es den Typ gibt. Und weil ein Coverage-Floor oder ein ähnliches Gate das ganze Projekt misst, nicht die Dateien, die ein Branch berührt hat, führt die Suite jedes solche Gate deiner CI vollständig aus, bevor sie den Merge Request öffnet.

Warum hat PHPMD keine Baseline?

Eine Baseline ließe die bestehenden Befunde nur als Liste aus Regel, Datei und Methode im Blick. Sie hält keinen Wert und keinen Grund fest, also bleibt eine Methode, die schlechter wird, nachdem sie in die Baseline kam, still, und niemand kann sagen, warum ein Eintrag da ist. Die Suite setzt jedes Limit der PHPMD-Metriken auf den schlechtesten Wert, den der Code heute hat, und senkt es, sobald die Arbeit diesen Wert beseitigt – die Limits selbst sind also der Nachweis der Schulden. Eine Ausnahme, die gewollt ist, steht am Code, mit ihrer Begründung daneben. Eine Regel mit zu vielen Befunden, um sie in einem reviewbaren Merge Request zu beheben, wartet, in der Konfiguration markiert, und wird Regel für Regel übernommen; du wirst nicht gebeten, sie aufzugeben. Der Preis ist, dass PHPMD auf einem Projekt mit nachgezogenen Limits nichts meldet, deshalb läuft die Suche nach Kandidaten stattdessen mit PHPMDs Standard-Limits.

Warum braucht PHP CS Fixer zwei Stufen?

Auf einem Projekt mit tausend Dateien ist ein einziger Formatierungsdurchgang ein Merge Request, den niemand reviewen kann, und die Pfade der Konfiguration einzuschränken, um ihn zu verkleinern, würde auch jede Regel fallen lassen, die auf den ausgelassenen Pfaden schon gilt. Deshalb bringt die Adoption das Preset und die Regeln mit, die in einen Merge Request passen, und schaltet die anderen mit einer Markierung ab. Eine zweite Konfigurationsdatei nimmt dann eine Regel nach der anderen auf, Pfad für Pfad. Die Aufteilung in zwei Stufen verhindert, dass der lange Rest Rector aufhält, das nur auf die Adoption wartet, und verschiebt den Rest nach Guardrails, wo er auch strukturelle Arbeit nicht aufhält. Der Preis ist, dass Rector und strukturelle Änderungen eine Zeit lang auf Code laufen, der nur teilweise formatiert ist; ein Konflikt dort wird gelöst, indem man den Fixer erneut laufen lässt.

Warum muss jeder Test sagen, was er abdeckt, und darf mein Coverage-Floor dafür sinken?

Ein Coverage-Bericht zählt eine Klasse als abgedeckt, wenn irgendein Test sie ausführt, auch der Test einer anderen Klasse, der nur durch sie hindurchläuft. Die Suite liest diese Zahlen, um Code ohne Tests zu finden, und eine solche Klasse sieht getestet aus, obwohl niemand sie testet. Deshalb schlägt die Suite nach dem Coverage-Floor zwei weitere Stufen vor: Jeder Test nennt die Klasse, die er abdeckt, und dann, auf PHPUnit 10 oder neuer, auch, was er nur nutzt, sodass ein Test fehlschlägt, der Code ausführt, den er nicht nennt. Integrations- und funktionale Tests werden als mittlere und große Tests markiert, die PHPUnit von dieser zweiten Prüfung ausnimmt: Sie laufen mit echten Kollaborateuren und brauchen keine Liste von allem, was dahintersteckt. Zwei Stufen, weil PHPUnit jede Prüfung für die ganze Testsuite auf einmal einschaltet und keine Baseline dafür hat.

Nur zu zählen, was ein Test testen will, kann die gemessene Coverage senken. Der Merge Request schreibt die fehlenden Tests, damit der Floor hält. Wo das mehr als ein reviewbarer Merge Request ist, misst er den Floor neu und setzt ihn auf den neuen Wert, einmal, und sagt das: den alten und den neuen Wert und die Klassen, die ohne Test bleiben. Es ist das eine Mal, dass der Floor sinkt, weil sich geändert hat, was gemessen wird, nicht die Tests.

Warum warten PHPStan Level 4 und 5 auf Rector?

Weil Rector einen Teil ihrer Baseline mechanisch abräumt, und jeder Befund, den es abräumt, ist einer, den niemand von Hand behebt. Level 4 meldet toten Code – unerreichbare Anweisungen, Bedingungen und Typprüfungen, die immer wahr oder falsch sind –, und Rectors Dead-Code-Set entfernt genau das, also wartet Level 4, bis über dieses Set entschieden ist. Level 5 prüft die Typen der Argumente, die an Methoden und Funktionen übergeben werden; sobald Rectors Type Coverage die Typen deklariert hat, die sie ableiten kann, wird Level 5 einmal gegen sie gemessen, nicht gegen Docblocks behoben, die die Umschreibungen später ersetzen, also wartet Level 5 auf Type Coverage. Die beiden Tools sind dafür gedacht, Seite an Seite eingesetzt zu werden. Das Rector-Set abzulehnen gibt das Level frei; es wird dann ohne die Umschreibungen übernommen. Rectors PHPUnit-Set berührt nicht, was die Levels prüfen, und ist eine Guardrails-Stufe: Es schreibt nur Testcode um, und ein Konflikt mit struktureller Arbeit wird gelöst, indem man Rector erneut laufen lässt.

Warum hört Rector bei der PHP-Version auf, die mein Projekt deklariert?

Weil den Code für ein neueres PHP umzuschreiben dasselbe Versprechen ist wie das Minimum in der composer.json anzuheben: Danach läuft der Code nicht mehr auf dem älteren PHP. Wer dein Paket installiert oder deine Anwendung auf diesem PHP betreibt, hat danach kaputten Code, obwohl die composer.json es noch als unterstützt angibt. Das Minimum anzuheben ist eine Produktentscheidung, also trifft die Suite sie nie, weder in der composer.json noch über Rector. Rectors PHP-Set geht bis zu der Version, die du deklarierst; hebst du sie selbst an, bietet die nächste Nachprüfung des Toolings die nächste Stufe an. Code, der schon vor der Suite ein neueres PHP brauchte, wird als gewöhnliches Ticket vorgeschlagen, damit du entscheidest, ob das Minimum steigt oder der Code nachgibt.

Warum vergleicht die Suite manchmal den alten und den neuen Code an echten Eingaben?

Ein Test deckt nur die Fälle ab, an die jemand gedacht hat. Reicht ein Umbau über mehrere Schritte hinter eine Kante und ist das Ergebnis etwas Vergleichbares – Text, eine Datei, Daten –, kann der erste Commit stattdessen ein Skript sein: Es lässt den Code, wie er war, und den Code, wie er jetzt ist, auf den eigenen Beispieleingaben des Projekts laufen und vergleicht, was herauskommt. Ein Unterschied ist ein Fehler in der Änderung, denn ein Refactoring erlaubt keinen. Es nutzt nur, was das Projekt schon hat – Fixtures, Beispieldateien, Eingaben seiner Tests – und nie Produktionsdaten; ohne brauchbare Eingabe hält ein gewöhnlicher Test das Verhalten fest. Das Skript wird danach weggeworfen, es sei denn, es wäre weiterhin ein guter Test.

Warum sind manche Dinge Regeln und andere nur Prinzipien?

Eine Regel ist, woran sich ein Run ohne Ausnahme halten muss, und sie lässt sich prüfen: Ein Refactoring erhält das Verhalten, ein Tool tut, was ein Tool tun kann, Arbeit passiert auf einem eigenen Branch, ein Test hält das Verhalten zuerst fest. Ein Prinzip hilft bei einer Abwägung, die vom Code abhängt – ob eine Migration Alt und Neu nebeneinander braucht, ob eine Änderung den Code leichter nachvollziehbar macht. Ein Agent wägt es ab und sagt im Plan oder im Review, welches eine Entscheidung verändert hat. Solche Abwägungen als Regeln zu behandeln, erzeugt Änderungen, die korrekt sind und nichts verbessern – deshalb wird eine Änderung, die den Code nicht leichter nachvollziehbar macht, wieder herausgenommen.

Warum werden nicht alle Befunde des Reviews behoben?

Das eigene Review der Suite sortiert, was es findet. Ein Befund, den die Slices des Plans beheben können, geht zum Beheben zurück. Einer, der stimmt, aber mehr braucht als der Plan, wird im Merge Request genannt und liegen gelassen, damit die Änderung die Größe behält, der du zugestimmt hast. Einer, der sich als keiner herausstellt, weil der dokumentierte Standard deines Projekts das Muster gutheißt, wird mit seiner Begründung im Abschlussbericht verworfen. Was der Plan nicht verlangt hat, oder eine Änderung an dem, was die Anwendung tut, wird nie verworfen. Die Suite hält bei den Grauzonen nicht an, um zu fragen, weil ein autonomer Run nicht antworten könnte; der Abschlussbericht listet jede Verwerfung auf, sodass du oder der Agent, der den Run gestartet hat, eine davon kippen könnt.

Warum gibt ein Run auf, wenn derselbe Fehler wiederkommt, und nicht nach einer Anzahl von Versuchen?

Eine feste Anzahl von Runden ist willkürlich: Zwei können für einen schweren Bug zu wenige und für eine Sackgasse zu viele sein. Dass ein Run festhängt, zeigt sich daran, dass derselbe Check rot bleibt oder derselbe Review-Befund wiederkommt, nach einem Fix und dann nach einem zweiten Versuch. An diesem Punkt hört die Suite auf, behält den Branch bei sich, ohne ihn zu pushen, hinterlässt auf dem Ticket eine Schilderung in klaren Worten und wartet auf deine Antwort. Sie macht einen Check nie grün, indem sie ihn löscht oder lockert.

Warum wird die alte API manchmal neben der neuen behalten und manchmal sofort gelöscht?

Das hängt vom Versprechen deines Projekts an den Code außerhalb davon ab – an die Nutzer deines Pakets, die Addons deiner Anwendung. Wo dein BC-Versprechen die alte Schnittstelle abdeckt, ersetzt die Suite sie Stück für Stück, behält Alt und Neu nebeneinander und markiert die alte als deprecated, so wie dein Versprechen es sagt; sie löscht sie nie, denn das würde jemanden brechen, den das Versprechen schützt. Das Entfernen kommt später als gewöhnliches Ticket für dich, wenn dein Versprechen es erlaubt. Wo jeder Aufrufer im Projekt liegt und das Versprechen sie nicht abdeckt, zieht die Suite alle Aufrufer um und löscht die alte API im selben Schritt, sodass keine Kompatibilitätsschicht zurückbleibt. Der Plan sagt, welchen Fall sie vorgefunden hat.

Was ist das BC-Versprechen, und warum fragt die Suite danach?

Es ist das eigene Dokument deines Projekts, das sagt, welche Teile des Codes für Code außerhalb des Projekts stabil bleiben und wie eine inkompatible Änderung erlaubt ist: eine neue Major-Version unter SemVer oder eine Deprecation-Frist, gezählt in Releases und Monaten, wie manche Anwendungen sie ihren Addons versprechen. Die Suite modelliert keins von beiden; sie liest dein Dokument. Sie fragt einmal, beim Onboarding oder zu Beginn des nächsten Runs, denn mehrere Entscheidungen hängen an der Antwort, und eine falsche Annahme lässt sich nicht rückgängig machen, indem man ein Ticket ablehnt: Eine API zu löschen, die deine Addons nutzen, ist ein Bruch, eine API zu behalten, die außerhalb niemand nutzt, ist Ballast. Sie schlägt das Dokument vor, das sie gefunden hat, oder „keins“. Bis du antwortest, behandelt sie Code, der von außen erreichbar ist, als abgedeckt.

Warum wird der Backward-Compatibility-Check nur für ein SemVer-Versprechen eingerichtet?

Weil der Check, Roaves Backward Compatibility Check, deinen Code mit dem letzten Release vergleicht und jede entfernte oder geänderte Methode als Bruch meldet. Unter SemVer ist das genau die Regel: Ein Bruch wartet auf die nächste Major-Version. Unter einem Versprechen, das in Zeit und Releases zählt, ist ein Entfernen nach der Deprecation-Frist erlaubt, und der Check würde bei jedem fehlschlagen, bis ihm jemand sagt, es zu ignorieren. Außerdem findet er das letzte Release nur in einem Tag wie 1.4.2. Deshalb wird er eingerichtet, wo dein Versprechen SemVer folgt und du ein Release getaggt hast, und bevor die eigenen Restrukturierungen der Suite beginnen, denn die sind es, die deine Nutzer brechen könnten. Wo ein Typ, den die Suite hinzufügt, eine Unterklasse in fremdem Code brechen könnte, nimmt Rectors Type Coverage einen BC-sicheren Weg, der nicht finale public und protected Methoden in Ruhe lässt.

Warum tut die Suite nicht einfach, was ein Review-Bot verlangt?

Ein Bot findet echte Fehler und schreibt auch Kommentare, die falsch oder nur Rauschen sind, und auf alle einzugehen, erzeugt Änderungen, die niemand wollte. Deshalb prüft die Suite jeden Bot-Kommentar zuerst, führt den Test oder Befehl aus, den er nennt, wo das billig ist, und sortiert ihn: beheben, mit einer konkreten Begründung verwerfen oder dich fragen. Alles, was Sicherheit, Daten, Berechtigungen, Migrationen oder Nebenläufigkeit betrifft, wird erfragt, nie verworfen. Ein Kommentar von einem Menschen ist etwas anderes: Er wird behoben oder beantwortet, und die Suite verwirft ihn nie von sich aus. Unter jedem Kommentar, den sie bearbeitet, hinterlässt sie eine kurze Antwort, und sie markiert Threads nicht als gelöst – das ist Sache des Reviewers.

Warum sagt ein Merge Request, warum eine Änderung sicher ist?

Der Test, der das Verhalten festhält, deckt ab, was ein Nutzer des Codes sieht. Eine Umbenennung, eine Verschiebung oder eine Löschung kann trotzdem etwas brechen, das der Test nie erreicht: einen Namen in einem String, eine Konfigurationsdatei, einen Container-Eintrag, gespeicherte Daten. Wo eine Änderung einen solchen Namen berührt, nennt die Beschreibung deshalb die eine Tatsache, derentwegen sie sicher ist, und wie weit das belegt wurde – im Quellcode nachgelesen, gezeigt, dass der schlechte Fall nicht eintreten kann, ausgeführt oder in der Anwendung nachgestellt. Was sich nicht belegen ließ, wird als unbelegt benannt, damit der Reviewer weiß, wo er hinschauen muss. Andere Änderungen bekommen keinen solchen Absatz.

Ich habe eine offene Frage auf einem Ticket beantwortet – was passiert jetzt?

Jeder Kommentar, der neuer ist als der Open question-Kommentar der Suite, beendet das Warten, es sei denn, er ist ein weiterer Plan oder eine weitere Open question der Suite. Wer ihn geschrieben hat, zählt nicht: Agenten posten oft mit deinem eigenen Account, also geht die Suite danach, was ein Kommentar sagt. Der nächste Run liest deine Antwort: Bestätigt sie die Voreinstellung, mit der der Plan gemacht wurde, bleibt der Plan stehen; nennt sie einen anderen Weg, plant die Suite damit neu; lehnt sie das Ticket ab, wird die Ablehnung festgehalten; ist die Frage noch offen, wirst du noch einmal gefragt. Es gibt kein Label zu setzen oder zu entfernen, das funktioniert also auch auf einem Tracker ohne Triage-Labels.

Warum „Safety Net“ und „Tooling-Baum“?

Der Tooling-Baum ist das zugrunde liegende Modell: die Tools, die ein Projekt einführen kann, jedes in Schritten. „Safety Net“ benennt den Teil davon, der geklärt sein muss, bevor strukturelle Arbeit beginnt – deterministische Checks wie ein Testrunner und statische Analyse –, und benennt außerdem den Track, der sie einrichtet. Guardrails ist der Teil, der danach kommt. Das eine ist die Karte, das andere benennt Regionen darauf.

Warum denkt die Suite in Rollen und Tools statt nur in einer Liste von Schritten?

Weil Tools konkurrieren und Projekte sich unterscheiden. Zwei Tools können dieselbe Aufgabe erledigen – PHPStan und Psalm, PHP CS Fixer und Pint –, und einem Projekt, das schon eines nutzt, sollte das andere nicht angeboten werden. Deshalb benennt die Suite die Aufgabe (eine Rolle, etwa statische Analyse), die Tools, die sie erledigen können, und die Schritte jedes Tools. Ein Projekt mit Psalm hat die Rolle besetzt und bekommt PHPStan nie angeboten; ein abgelehntes Tool lässt die Rolle für ein anderes offen; eine abgelehnte Rolle schließt jedes Tool dafür. Dieselbe Form erlaubt es, ein Projekt in einer anderen Sprache oder ein Tool, das die Suite nicht kennt, als Daten hinzuzufügen statt als Änderung an der Suite.

Wie füge ich ein Tool hinzu, das die Suite nicht kennt?

Halte ein eigenes Pack: eine pack.json mit dem Tool und seinen Schritten, eine Markdown-Datei, die sagt, wann ein Schritt erfüllt ist, und einen Punkt Tooling Pack in deiner Tracker-Datei, der das Verzeichnis nennt. Die Suite schlägt deine Schritte vor wie ihre eigenen, und ein Tool von dir, das die Aufgabe eines ihrer Tools erledigt, steht daneben (lehne das der Suite ab, wenn du deines vorziehst). Es fügt hinzu, es definiert nie um, und es nennt die Sprache, auf der es arbeitet, damit ein Tool für Twig nicht den Platz eines Tools für PHP einnimmt. Das Playbook hat ein ausgearbeitetes Beispiel.

Ist es mit anderen Engineering-Skills kompatibel?

Ja, und mit ihnen ist es besser. Ein Run empfiehlt die eigenen Skills eines Projekts fürs Planen und Umsetzen, etwa die aus mattpocock/skills, gegenüber seinen eigenen Verfahren und liest eine Issue-Tracker-Datei, die sie geschrieben haben. Nutze die Skills, denen du ohnehin vertraust. Keiner ist nötig: Ohne sie schreibt der erste /continuous-refactoring diese Datei selbst, und der Run plant und setzt auf seine eigene Weise um.

Welche Issue-Tracker funktionieren?

Jeder Tracker, den ein Agent erreichen kann, solange docs/agents/issue-tracker.md ihn beschreibt. GitHub, GitLab und lokale Markdown-Dateien bringen eine Vorlage mit, das Onboarding fragt also nichts über ihre Operationen. Für einen anderen Tracker bietet das Onboarding drei Wege an: ihn so nutzen, wie diese Datei ihn bereits beschreibt, ihn direkt im Interview beschreiben, oder Refactoring-Tickets als lokale Markdown-Dateien führen, während alles andere bleibt, wo es ist.

Die Suite fragt nach einer Handvoll Operationen, statt jeden Tracker beim Namen zu kennen, weil das alles ist, was sie braucht: wie Tickets gesucht werden, wie ein erledigtes erkannt wird, wo Merge Requests liegen. Tickets und Merge Requests können auch in zwei Systemen liegen; die Suite findet den Merge Request eines Tickets dann durch eine Suche in der Forge.

Kann ich das Onboarding erneut ausführen?

Es läuft von selbst erneut, wann immer dem Tracker-Abschnitt eine Operation fehlt, die die Suite verlangt – so bekommt ein mit einer früheren Version eingerichtetes Projekt, was ihm fehlt. Was schon festgehalten ist, bleibt und wird nicht erneut gefragt; nur das Fehlende wird geschrieben. Bei einem vollständigen Abschnitt hat das Interview nichts zu fragen: Ändere einen Punkt dort, indem du docs/agents/issue-tracker.md selbst bearbeitest.

Wie stelle ich ein Projekt von 0.6.0 um?

Drei Schritte: das Onboarding erneut ausführen; die alten Zustandsdateien der Suite in ihrem Scratch-Ordner löschen, die nicht mehr gelesen werden; die Symlinks der Skills entfernen, die es nicht mehr gibt. Nichts wird migriert – der erste Scan jedes Tracks baut die Arbeitsliste als Tickets neu auf. Um alte Ablehnungen dort zu behalten, wo sie sind, nenne diesen Ordner in deinem Tracker-Abschnitt als Ort für Ablehnungen. Das README listet die Dateien.

Wie bringe ich einen Run dazu, an einem bestimmten Track oder Ticket zu arbeiten?

Nenne es im Aufruf: „arbeite an Guardrails“, „Ticket 42“. Der Run bleibt dann dabei und endet, wenn es nichts zu bearbeiten hat. Details: Track-Playbook.

Ein genanntes Ticket grenzt auch ein, was sich der Run vorher ansieht: Er sucht nach keinem anderen Ticket und gleicht nur den Merge Request dieses Tickets ab. Ein Run, den du für ein Ticket gestartet hast, schreibt nichts an die anderen und durchsucht nicht vorher den ganzen Tracker. Merge Requests anderer Tickets, die inzwischen gemergt oder geschlossen wurden, und abgelehnte Arbeit, deren Blocker erfüllt ist, warten auf den nächsten Run, der kein Ticket nennt.

Was passiert, wenn es kein Remote und keine Forge gibt?

Der Run geht trotzdem so weit, wie er kann: Er bereitet den Branch und seine Commits vor, nennt den Branch in einem Kommentar auf dem Ticket und übergibt ihn dir – zum selbst Mergen, oder zum Pushen und Öffnen des Merge Requests, sobald es eine Forge gibt. Er committet nie auf den Default-Branch. Spätere Runs lesen den Branch-Namen aus dem Ticket und behandeln das Ticket als im Review, bis der Branch gemergt ist.

Entscheidet die Suite anhand von Dependency-Namen, ob ein Tool schon adoptiert ist?

Nein. Die Erfüllung wird von einem Agenten am Zweck jedes Tools beurteilt, ein von Hand adoptiertes Tool – oder ein Äquivalent unter anderem Namen – zählt also, und sein Ticket wird mit einer Notiz geschlossen, statt bearbeitet zu werden. Der Parser berechnet nur die Graphenlogik des Baums.