# 0.10.0: Tools auf Anfrage, dein BC-Versprechen und ein Agent, der steuert

*28. Oktober 2026 · Release · geschrieben für 0.10.0*

Bei 0.10.0 geht es darum, **das Richtige vorzuschlagen, und weniger
davon**. Manche Tools werden jetzt nur noch eingerichtet, wenn du danach
fragst, die Suite erfährt, was dein Projekt dem Code außerhalb davon
verspricht, und ein Run lässt sich von einem anderen Agenten steuern. Es
gibt eine inkompatible Änderung, nur für ein eigenes Pack: `after` einer
Stufe heißt jetzt `waits_for`. Alles andere braucht nichts von dir; was dir
auffallen wird, steht am Ende unter
[Was sich für dein Projekt ändert](#was-sich-für-dein-projekt-ändert).

## Tools auf Anfrage

Bis 0.9 schlug jeder Scan jedes Tool vor, das weder eingerichtet noch
abgelehnt war. Bei manchen Tools war das Rauschen. Semgrep findet viel in
Code, der jahrelang ohne Guardrails gewachsen ist, und fast nichts in einem
jungen Projekt, das sie von Anfang an hatte. Mutation Testing führt deine
Tests hunderte Male aus, was sich erst lohnt, wenn sie gut genug sind, um
beurteilt zu werden.

Deshalb gibt es ein paar Tools jetzt **auf Anfrage**: Semgrep, die
Taint-Analyse von Psalm, Secret Detection und das neue Mutation Testing mit
Infection. Sie werden nie ungefragt angeboten und blockieren nie einen
Track. Jeder Scan-Bericht nennt, was auf Anfrage verfügbar ist; nenne eines
im Aufruf, und es wird vorgeschlagen wie jedes andere Tool:

```text
/continuous-refactoring richte Semgrep ein
/continuous-refactoring scanne inklusive der Tools auf Anfrage
```

Zwei Tools haben eher ihren Platz gewechselt als ihren Status:

- **Composer Audit gibt es nicht mehr als Tool.** Ein Pipeline-Check
  schlägt nur bei Advisories fehl, die bekannt sind, wenn sich der Code
  ändert; eines, das nächsten Monat gegen dasselbe Lockfile erscheint, wird
  nie gesehen. Die erste Housekeeping-Vorlage enthält jetzt ein
  wiederkehrendes **Dependency-Audit**, für jeden Paketmanager, und
  auditiert in jedem Zyklus.
- **Der Secret-Scan wartet nicht mehr auf einen Scanner in deinem
  Projekt.** Housekeeping nutzt den, den du hast, oder führt einen eigenen
  aus (etwa gitleaks), ohne deinem Projekt etwas hinzuzufügen. Der
  Push-Schutz einer Forge zählt als eingerichtete Secret Detection.

Die Diagramme auf den Pack-Seiten zeigen den Status eines Tools jetzt am
Rahmen seiner Stufen, gestrichelt für auf Anfrage, gepunktet für erkannt,
mit einer Legende darunter. Siehe [Pack php](https://continuous-refactoring.de/de/docs/pack-php.md).

## Dein BC-Versprechen

Ob die Suite eine alte API löschen darf, hängt davon ab, wer sie sonst noch
nutzt. Bis 0.9 hat sie geraten: Wo sie es nicht sagen konnte, nahm sie an,
dass jemand davon abhängt. Jetzt fragt sie. Das **BC-Versprechen** ist das
eigene Dokument deines Projekts, das sagt, was für Code außerhalb des
Projekts stabil bleibt, die Nutzer deines Pakets oder die Addons deiner
Anwendung, 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.

- **Das Onboarding fragt danach**, und ein Projekt, das schon vorher
  onboardet wurde, wird einmal zu Beginn seines nächsten Runs gefragt. Die
  Antwort, ein Pfad oder `none`, kommt in `docs/agents/issue-tracker.md`.
- **Code, den das Versprechen abdeckt**, wird mit Alt und Neu nebeneinander
  restrukturiert, und der alte Weg wird so als deprecated markiert, wie
  dein Versprechen es sagt. Sein Entfernen wird später als gewöhnliches
  Ticket vorgeschlagen, nie von einem Refactoring vorgenommen.
- **Unter einem SemVer-Versprechen mit getaggtem Release** bekommt das
  Safety Net Roaves Backward Compatibility Check, der in der CI läuft, bevor
  die Restrukturierungen der Suite beginnen. Rectors Type Coverage wartet
  darauf.
- **Wo dein Versprechen das Erweitern nicht finaler Klassen abdeckt** oder
  noch nicht geklärt ist, nimmt Rectors Type Coverage einen BC-sicheren
  Weg. Einer Methode einen Parameter- oder Rückgabetyp hinzuzufügen, bricht
  jede Klasse außerhalb deines Projekts, die sie überschreibt. Deshalb
  schaltet die Suite Rectors eigenes Type-Declaration-Set ab und nimmt
  stattdessen
  [`art4/rector-bc-library`](https://gitlab.com/Art4/rector-bc-library),
  eine Library, die ich maintaine: dieselben Regeln, aber nur dort angewendet, wo die Änderung keinen
  BC-Bruch bedeutet. Das Paket kommt als Dev-Abhängigkeit dazu und
  unterstützt dieselbe Einführung in Levels.

Die [FAQ](https://continuous-refactoring.de/de/docs/faq.md#was-ist-das-bc-versprechen-und-warum-fragt-die-suite-danach)
erklärt die Gründe.

## Tests, die sagen, was sie abdecken

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,
also sah eine solche Klasse getestet aus, obwohl niemand sie testete. Nach
dem Coverage-Floor folgen für PHP-Projekte zwei weitere Stufen:

- **Jeder Test nennt die Klasse, die er abdeckt.**
- **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 und
  brauchen keine solche Liste. Pest bietet keine Möglichkeit zu nennen, was
  ein Test nutzt, also endet es bei der ersten Stufe.

Nur zu zählen, was ein Test testen will, kann die gemessene Coverage
senken. Der Merge Request schreibt die fehlenden Tests; wo das nicht passt,
setzt er den Floor einmal auf den neu gemessenen Wert und sagt das.

Zwei verwandte Änderungen: Eine Restrukturierung, die eine neue Klasse
anlegt, gibt ihr jetzt einen eigenen Test, zuerst geschrieben, statt sich
darauf zu verlassen, dass der Test des alten Codes grün bleibt. Und bevor
ein Run einen Merge Request öffnet, führt er jedes Gate, das deine CI über
das ganze Projekt ausführt, etwa den Coverage-Floor, vollständig aus und
nennt jedes, das er lokal nicht ausführen kann.

## Rector vor PHPStan, und nie über dein PHP hinaus

- **PHPStan Level 4 wartet auf Rectors Dead-Code-Set, Level 5 auf Type
  Coverage.** Rector räumt einen Teil der Baselines dieser Levels
  mechanisch ab, und jeder Befund, den es abräumt, ist einer, den niemand
  von Hand behebt. Das Rector-Set abzulehnen gibt das Level frei.
- **Rectors PHP-Set hört bei der PHP-Version auf, die deine
  `composer.json` deklariert.** Den Code für ein neueres PHP umzuschreiben
  ist dasselbe Versprechen wie das Minimum anzuheben, und das ist eine
  Produktentscheidung. Die Stufe „PHP Version Floor“ ist damit weg; die
  Suite hebt dein deklariertes Minimum nicht mehr an.
- **Rectors PHPUnit-Set ist eine Guardrails-Stufe** und hält das Safety
  Net nicht mehr auf.

## Ein Agent, der die Runs steuert

`/continuous-refactoring` kann jetzt von einem Agenten gestartet werden,
wie es `/continuous-housekeeping` schon konnte. Das neue
[Driver-Playbook](https://continuous-refactoring.de/de/docs/driver.md) beschreibt einen solchen Agenten: Er
ruft einen autonomen Run nach dem anderen auf, jeden in einem eigenen
Subagenten, sodass jeder Run mit frischem Kontext beginnt, prüft jeden
Merge Request in einem zweiten Subagenten, mergt, was besteht (oder
kommentiert nur, wenn du „nur Review“ wählst), und fragt dich nur, wo die
Entscheidung bei dir liegt. Am Ende des Playbooks steht ein Prompt zum
Kopieren in dein Projekt.

Drei Änderungen machen das möglich und helfen jedem Run:

- **Ein genanntes Ticket grenzt den Run ein.** „Ticket 42“ durchsucht nicht
  mehr erst alle offenen Tickets, und der Abgleich prüft nur den Merge
  Request dieses Tickets. Ein Run, der für ein Ticket gestartet wurde,
  schreibt nichts an die anderen.
- **Eine offene Frage wird nach Inhalt beantwortet, nicht nach Autor.** Das
  Warten endet beim ersten Kommentar, der weder der Plan der Suite noch eine
  weitere ihrer Fragen ist, egal von welchem Account, denn Agenten posten
  oft mit deinem. Eine Antwort, die das Ticket ablehnt, wird als Ablehnung
  festgehalten.
- **Ein Tool, dessen Beurteilung offen bleibt**, wird mit seiner Frage am
  neuen Ticket angelegt, sodass ein autonomer Run es nicht mehr auslässt und
  bei jedem Scan erneut aufbringt.

Die [bekannten Einschränkungen](https://continuous-refactoring.de/de/docs/known-limitations.md) nennen die
zwei Haken: Der Kommentar eines Agenten an einem wartenden Ticket zählt als
deine Antwort, und ein Run in einem Subagenten macht seine Review-Schritte
im eigenen Kontext.

## Was sich für dein Projekt ändert

Eine Sache gibt es zu tun, nur wenn du ein **eigenes Pack** hast: Benenne den
Schlüssel `after` jeder Stufe in `waits_for` um. Ein Pack, das noch `after`
sagt, wird mit einer Meldung abgelehnt, die genau das sagt. Wenn du schon
dabei bist: Ein Tool von dir, das eine zweite Stufe bekommt, braucht einen
eigenen Slug; benenne das Tool um, nicht die Stufe, damit deine Tickets und
Ablehnungen ihre Namen behalten.

Was dir auffallen wird:

- **Der nächste Run fragt nach deinem BC-Versprechen**, einmal, und macht
  weiter.
- **Ein offenes Ticket „Composer Audit“ oder „PHP Version Floor“** wird zum
  Schließen angeboten, mit einer Notiz, was an seine Stelle getreten ist.
  Eine festgehaltene Ablehnung dieser Stufe wird einfach ignoriert.
- **Deine Housekeeping-Vorlage bekommt das Dependency-Audit** im nächsten
  Zyklus.
- **Offene Tickets für Semgrep, Psalm Taint Analysis oder Secret Detection
  bleiben** und werden bearbeitet wie bisher; nur neue Scans schlagen sie
  nicht mehr vor.
- **Der nächste Scan schlägt vielleicht neue Stufen vor**: die
  Coverage-Metadaten-Stufen und den Backward Compatibility Check, wenn dein
  Versprechen SemVer folgt.

Die [FAQ](https://continuous-refactoring.de/de/docs/faq.md) erklärt die Gründe, zum Beispiel
[warum manche Tools nur auf Anfrage eingerichtet werden](https://continuous-refactoring.de/de/docs/faq.md#warum-werden-manche-tools-nur-eingerichtet-wenn-ich-danach-frage)
und [warum Rector bei deiner PHP-Version aufhört](https://continuous-refactoring.de/de/docs/faq.md#warum-hört-rector-bei-der-php-version-auf-die-mein-projekt-deklariert).

Wenn du einen Driver auf eines deiner Projekte loslässt, freue ich mich,
in den
[GitHub Discussions (Show and tell)](https://github.com/Art4/continuous-refactoring/discussions/categories/show-and-tell)
zu lesen, wie es lief.

## Changelog 0.10.0

Die Einträge aus dem Upstream-Changelog zu 0.10.0, unverändert auf Englisch. Auch auf GitHub: [Release 0.10.0](https://github.com/Art4/continuous-refactoring/releases/tag/0.10.0).

- Semgrep and Psalm's taint analysis are no longer proposed to every project: they are now set up only when you ask for them, by naming one in the call ("set up Semgrep") or by asking for a scan including the tools on request, and each scan report names what is available. Composer Audit is no longer a tool to set up: the first Housekeeping template now carries a recurring dependency audit for any package manager, an existing template gains it on its next cycle, and an open "Composer Audit" or "PHP Version Floor" ticket is offered for closing with a note saying what took its place. The diagrams under docs/tooling now show a tool's status as the outline of its steps — dashed for on request, dotted for recognized — with a legend below.
- Secret Detection is now set up only on request, and the secret scan over the Git history no longer waits for it: Housekeeping uses your project's own secret scanner, or runs one of its own (gitleaks, for instance) without adding anything to your project. A forge's push protection for secrets now counts as Secret Detection being in place, and the scanner's findings no longer feed the Security signal of restructuring candidates.
- Mutation testing joins the tooling, on request: ask for Infection and the suite sets it up after your coverage floor, with a minimum score that only rises, a pipeline check on the changed files and a full run in each Housekeeping cycle; the faults your tests miss then point the search for restructurings at code that is run but not really tested. A project that already runs Pest's own mutation testing has it in place. A tool on request that needs a newer PHP than your project allows is no longer reported as out of reach until you ask for it.
- The suite now asks whether your project promises stability to code outside it — your package's users, your application's addons — and records where that promise is written (or that there is none) in `docs/agents/issue-tracker.md`. Onboarding asks it; a project onboarded before is asked once at the start of its next run. Code the promise covers is restructured with old and new side by side and the old path deprecated the way your promise says; its removal is proposed as an ordinary ticket, never made by a refactoring.
- A project whose BC promise follows SemVer and that has tagged a release now gets Roave's Backward Compatibility Check in its Safety Net, run in CI from its Docker image, before the suite's restructurings start. Rector's type coverage waits for it, and where your promise covers extending non-final classes it takes the BC-safe `art4/rector-bc-library` set instead of Rector's own, so an added type does not break a subclass in someone else's code.
- After the coverage floor, the suite now proposes two more steps for PHP projects: every test says which class it covers, and then — on PHPUnit 10 or newer, not on Pest — also what it only uses, so coverage counts only what a test means to test and a class without a test of its own shows up as untested. Integration and functional tests are marked as medium and large tests and need no list of what they use. The merge request writes the tests a class lacks; where that does not fit, it sets the coverage floor once to the newly measured value and says so. A Pack of your own whose Tool gains a second Stage is now told to rename the Tool, not the Stage, so tickets and rejections on record keep their name.
- Rector's PHP set now goes up to the PHP version your `composer.json` declares and never above it, and the "PHP Version Floor" step is gone: the suite no longer raises your declared minimum PHP after rewriting the code for a newer one. A rejection of that step you recorded earlier is ignored.
- PHPStan Level 4 now waits until Rector Dead Code is decided, and Level 5 until Rector Type Coverage is, so the rewrites shrink those levels' baselines before they are fixed by hand; Rector's PHPUnit Set is now a Guardrails Stage and no longer holds the Safety Net back.
- A Stage's `after` field in a Pack is now named `waits_for` ("B waits for A"), and the generated tooling tables call the column "Waits for". A Pack of your own that still says `after` is refused with a message asking you to rename the key.
- A structural change that creates a new class or other type reachable from outside now gives it a test of its own, written first, instead of relying on the old code's test staying green; and before opening a merge request a run now executes every gate your CI applies to the whole project, such as a coverage floor, in full, naming any it cannot run locally.
- A run whose call names a ticket now looks at that ticket alone: it no longer searches every open ticket first, and reconcile checks only that ticket's merge request, so it writes nothing to tickets you did not name.
- An open question on a ticket now ends at the first comment that is neither the suite's plan nor another of its questions, whichever account wrote it, and an answer that declines the ticket is recorded as a rejection.
- A proposed tool whose judgement stays open is now filed with its question as an open question on the new ticket, so an autonomous run no longer leaves it unfiled and raises it again on every scan.
- An agent may now start `continuous-refactoring` by itself, as it already could `continuous-housekeeping` — for example one that hands each run to a subagent and reviews its merge request before calling the next.
- A new Driver playbook describes an agent that calls runs one after another, each in a subagent of its own, reviews and merges each merge request in between, and asks you only where a decision is yours — with a prompt to copy into your project.
- Known limitations now name two effects of letting an agent drive runs: its comments on a waiting ticket count as your answer, and a run inside a subagent does every step in its own context.
- `docs/adr/README.md` lists every decision with its status — in force, amended, superseded in part or superseded — generated from the ADRs' banners, which the validator now keeps consistent on both sides of every relation.

---

Fragen oder Anmerkungen zu diesem Beitrag? Gern in den [GitHub Discussions (Q&A)](https://github.com/Art4/continuous-refactoring/discussions/categories/q-a).
