Öffentliches Register
Software-GesundheitsberichtSchema 0.27.0 · Metriken 1.13.0 · 2026-07-25 17:21 UTC

openrewrite / rewrite-testing-frameworks

OpenRewrite recipes that perform common Java testing migration tasks.

JavaEigene Lizenz★ 99 Sterne⑂ 104 Forksseit Sept. 2020Auf GitHub ansehen ↗

openrewrite/rewrite-testing-frameworks erreicht einen Gesundheitsindex von 72 von 100 und liegt damit im Bereich Gut. Am stärksten schneidet es bei Vitality (100/100) ab, am schwächsten bei Security (52/100). Zuletzt heute aktualisiert. 3 Mitwirkende tragen den Großteil der jüngsten Arbeit.

72
gesamt / 100
Gut

Software-Gesundheitsindex

Metriken werden auf einer Skala von 1–100 in gewichtete Kategorien gruppiert. Der Gesamtwert beginnt als ihr Mittel; sobald öffentliche Evidenz die Richtlinie für Hochrisikojurisdiktionen auslöst, wird die Bewertung angepasst und erhält die Obergrenze 49 (Gefährdet). AI Readiness liegt außerhalb.

72
Exzellent85-100Vorbildlich; erfüllt im Wesentlichen alle geprüften Kriterien
Gut70-84Gesund; geringfügige Lücken
Mittel50-69Akzeptabel mit deutlichen Lücken; Überprüfung empfohlen
Gefährdet30-49Erhebliche Schwächen; eine Übernahme erfordert Vorsicht
Kritisch1-29Schwerwiegende Probleme (aufgegeben, nur ein Maintainer, keine Hygiene)
VitalitätCommunity &VerbreitungNachhaltigkeit &GovernanceEngineering-QualitätSicherheitAI Readiness

Bewertungsprofil

Jede Achse ist eine Kategorie. Die Form zählt mehr als der Durchschnitt — ein gesundes Projekt füllt die gesamte Fläche, während ein Profil aus Spitzen und Kratern bedeutet, dass Stärke in einer Dimension Risiken in einer anderen verdeckt.

Eigentümerschaft

OpenRewriteOrganisation
984 Follower75 öffentliche Reposseit Feb. 2020

Dieses Repository wird von einer Organisation getragen — geteilte, rechenschaftspflichtige Trägerschaft, die jeden einzelnen Maintainer überdauern kann.

Metriken nach Kategorie

Vitalität

Lebt das Projekt — wird Code geschrieben und werden Releases ausgeliefert?

100Exzellent · 22 % des Gesamtindex
Wie die Bewertung erfolgt
36/36Push-Aktualität — letzter Push vor 0 Tagen
36/36Commit-Rhythmus — 52/52 Wochen mit Commits
18/18Commit-Volumen — 314 Commits im letzten Jahr
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 12 issue activity found in the last 90 days -- score normalized to 10
Verwendete Eingangsdaten
commits_last_year314
human_commit_share1
days_since_last_push0
active_weeks_last_year52

Release-Disziplin

100Exzellent
Wie die Bewertung erfolgt
27/27Liefert Releases aus — 100 Releases veröffentlicht
36/36Release-Aktualität — letztes Release vor 5 Tagen
27/27Release-Rhythmus — ein Release etwa alle 9,4 Tage
0/10OpenSSF Scorecard: Signed-Releases — keine Daten
Verwendete Eingangsdaten
releases_count100
latest_release_tagv3.42.1
releases_from_tagsnein
days_since_latest_release5
mean_days_between_releases9,4
Von der Bewertung ausgeschlossen (keine Daten oder nicht anwendbar): OpenSSF Scorecard: Signed-Releases. Die verbleibenden Gewichte wurden renormalisiert.

Community & Verbreitung

Hat das Projekt Nutzer, Downloads, Aufmerksamkeit und ein einladendes Umfeld für Beitragende?

61Mittel · 18 % des Gesamtindex
Wie die Bewertung erfolgt
32.3/60Stars — 99 Stars
16.8/25Forks — 104 Forks
4.3/15Watcher — 7 Watcher
Verwendete Eingangsdaten
forks104
stars99
watchers7
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Wie die Bewertung erfolgt
22.5/22.5README
16.9/22.5Lizenz — Lizenzdatei vorhanden, keine anerkannte Lizenz
18/18CONTRIBUTING-Leitfaden
0/13.5Verhaltenskodex
0/7.2Issue-Vorlage
6.3/6.3PR-Vorlage
Verwendete Eingangsdaten
has_readmeja
has_licenseja
has_contributingja
has_issue_templatenein
has_code_of_conductnein
has_pull_request_templateja

Nachhaltigkeit & Governance

Überdauert das Projekt die Menschen, die es tragen — Bus-Faktor, Reaktionsfähigkeit, Trägerschaft und Paketpflege?

77Gut · 24 % des Gesamtindex
Wie die Bewertung erfolgt
36/54Bus-Faktor — 3 Beitragende decken die Hälfte aller Commits ab
15.3/22.5Commit-Verteilung — wichtigste beitragende Person verfasste 32 % der Commits
13.5/13.5Breite der Beitragenden — 98 Beitragende
10/10OpenSSF Scorecard: Contributors — project has 16 contributing companies or organizations
Verwendete Eingangsdaten
bus_factor3
contributors_sampled98
top_contributor_share0,318
Wie die Bewertung erfolgt
43.9/46.8Issue-Lösungsquote — 94 % der Issues geschlossen
34.4/38.3PR-Annahme — 603/671 entschiedene PRs gemergt
3/15OpenSSF Scorecard: Code-Review — Found 8/30 approved changesets -- score normalized to 2
Verwendete Eingangsdaten
merged_prs603
open_issues23
closed_issues361
issue_closed_ratio0,94
closed_unmerged_prs68
Wie die Bewertung erfolgt
30/30Organisatorische Trägerschaft — im Besitz einer Organisation
0/20Verifizierte Domain
21.5/25Reichweite des Inhabers — 984 Follower von openrewrite
25/25Kontohistorie — 75 öffentliche Repos, Kontoalter ca. 6 Jahre
Verwendete Eingangsdaten
followers984
owner_typeOrganization
is_verified
owner_loginopenrewrite
public_repos75
account_age_days2.341

Engineering-Qualität

Sind grundlegende Engineering- und Dokumentationspraktiken vorhanden?

63Mittel · 20 % des Gesamtindex
Wie die Bewertung erfolgt
24/24CI-Workflows — 4 Workflow(s)
24/24Tests vorhanden
0/16Linter-Konfiguration
0/9.6Pre-Commit-Hooks
6.4/6.4.editorconfig
18/20OpenSSF Scorecard: CI-Tests — 22 out of 23 merged PRs checked by a CI test -- score normalized to 9
Verwendete Eingangsdaten
has_cija
has_testsja
has_editorconfigja
has_linter_confignein
has_precommit_confignein
Wie die Bewertung erfolgt
30/30README
0/25Dokumentationsverzeichnis
0/15Dokumentations-/Homepage-Site
10/10Repository-Beschreibung
10/10Topics — 2 Topics
0/10Wiki
Verwendete Eingangsdaten
topicsopenrewrite, openrewrite-recipes
has_wikinein
homepage
has_readmeja
has_docs_dirnein
has_descriptionja

Sicherheit

Sind die sichtbaren Sicherheits- und Lieferkettenpraktiken belastbar, ohne ungeklärte Exposition gegenüber Hochrisikojurisdiktionen?

52Mittel · 16 % des Gesamtindex
Wie die Bewertung erfolgt
6.8/7.5Binary-Artifacts — binaries present in source code
0/7.5Branch-Protection — branch protection not enabled on development/release branches
2.2/2.5CI-Tests — 22 out of 23 merged PRs checked by a CI test -- score normalized to 9
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
1.5/7.5Code-Review — Found 8/30 approved changesets -- score normalized to 2
2.5/2.5Contributors — project has 16 contributing companies or organizations
10/10Dangerous-Workflow — no dangerous workflow patterns detected
7.5/7.5Dependency-Update-Tool — update tool detected
0/5Fuzzing — project is not fuzzed
2.2/2.5Lizenz — license file detected
7.5/7.5Maintained — 30 commit(s) and 12 issue activity found in the last 90 days -- score normalized to 10
0/5Packaging — keine Daten
0/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
0/5SAST — SAST tool is not run on all commits -- score normalized to 0
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — keine Daten
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
7.5/7.5Vulnerabilities — 0 existing vulnerabilities detected
Verwendete Eingangsdaten
sourceopenssf_scorecard
checks_evaluated16
scorecard_versionv5.5.0
checks_inconclusive2
scorecard_aggregate5,2
Von der Bewertung ausgeschlossen (keine Daten oder nicht anwendbar): packaging, signed_releases. Die verbleibenden Gewichte wurden renormalisiert.

AI Readiness

Wie gut ist das Repository dafür ausgestattet, mit KI-Coding-Agenten entwickelt und gepflegt zu werden? Ein unabhängiges, experimentelles Badge — Gewicht 0,0, es wird eigenständig ausgewiesen und verändert den Gesamt-Gesundheitswert nicht.

58Mittel · 0 % des Gesamtindex
Wie die Bewertung erfolgt
0/45Agentenanweisungen — keine CLAUDE.md / AGENTS.md / Editor-Regeln
0/15Maschinenlesbare Doku (llms.txt)
40/40Lesbare Commit-Historie — 90 von 100 menschlichen Commits benennen ihre Absicht (strukturierter Betreff oder erläuternder Text)
Verwendete Eingangsdaten
has_llms_txtnein
legible_history_share0,9
agent_instruction_files
agent_instruction_max_bytes
Wie die Bewertung erfolgt
12.6/18Bootstrap mit einem Befehl — build.gradle.kts (Toolchain-Konvention, kein Task-Runner)
22/22Automatisierte Tests
0/11Lint-/Format-Konfiguration
11/11Statische Typprüfung — Java (statisch typisiert)
0/10Reproduzierbare Umgebung
4/10Belegte Agentenpraxis — 2 der letzten 100 Commits von Agenten verfasst oder ihnen zugeschrieben
5/8Automatisierte Wartung — Abhängigkeits-Automatisierung konfiguriert, in den erfassten Commits nicht beobachtet
0/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
Verwendete Eingangsdaten
has_nixnein
has_testsja
lockfiles
has_dockerfilenein
typed_languageja
bootstrap_files
has_devcontainernein
has_linter_confignein
typecheck_configs
agent_commit_share0,02
toolchain_manifestsbuild.gradle.kts
dependency_bot_commit_share0
Wie die Bewertung erfolgt
45/45Typprüfbarer Code — Java (statisch typisiert)
54.6/55Handhabbare Dateigrößen — 3/402 Quelldateien über 60 KB
Verwendete Eingangsdaten
primary_languageJava
largest_source_bytes73.880
source_files_sampled402
oversized_source_files3

Eckdaten

99GitHub-Sterne
98Mitwirkende
314Commits, letzte 12 Monate
0Tage seit letztem Push
100Releases
3Bus-Faktor
23offene Issues
MavenPaket-Ökosysteme

Warnungen zur Datenerhebung

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token
  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Weitere Details

Stern- und Fork-Verlauf 0 ★ / 104 ⇿
0Sterne
104Forks
100Releases

Wann jeder Stern und Fork hinzugefügt wurde, von GitHub erfasst und nach Tagen gruppiert. Das kumulierte Wachstum steht direkt über den täglichen Zugängen, aus denen es besteht, sodass beide gegeneinander lesbar sind: stetiger organischer Zuwachs sieht ganz anders aus als ein abrupter, kurzlebiger Ausschlag. Wo dieser Unterschied messbar ist, wird er als Wachstumsauthentizität ausgewiesen.

02040608010012010242020-122023-092026-07
Major 1Minor 66Patch 33

Jeder Punkt umfasst 6 Tage.

OpenSSF Scorecard 5.2 / 10
5.2Gesamtwert

Unabhängige, werkzeugneutrale Sicherheitsbewertung durch das quelloffene OpenSSF Scorecard. Jede Prüfung honoriert eine Sicherheits-Praxis, nicht das Werkzeug eines bestimmten Anbieters. Prüfungen, die Scorecard nicht ermitteln konnte, sind mit k. A. markiert und vom Sicherheitswert ausgeschlossen (nie als null gezählt).Scorecard v5.5.0 · 2026-07-25 17:21 UTC

9Binary-Artifactsbinaries present in source code
0Branch-Protectionbranch protection not enabled on development/release branches
9CI-Tests22 out of 23 merged PRs checked by a CI test -- score normalized to 9
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
2Code-ReviewFound 8/30 approved changesets -- score normalized to 2
10Contributorsproject has 16 contributing companies or organizations
10Dangerous-Workflowno dangerous workflow patterns detected
10Dependency-Update-Toolupdate tool detected
0Fuzzingproject is not fuzzed
9Licenselicense file detected
10Maintained30 commit(s) and 12 issue activity found in the last 90 days -- score normalized to 10
k. A.Packagingpackaging workflow not detected
0Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 0
0SASTSAST tool is not run on all commits -- score normalized to 0
0Security-Policysecurity policy file not detected
k. A.Signed-Releasesno releases found
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
10Vulnerabilities0 existing vulnerabilities detected
Alle Abhängigkeiten nicht erhoben

Der aufgelöste Abhängigkeitssatz konnte für diesen Bericht nicht erhoben werden: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

JSON-Rohbericht maschinenlesbar
{
  "data": {
    "repo": {
      "topics": [
        "openrewrite",
        "openrewrite-recipes"
      ],
      "is_fork": false,
      "size_kb": 64085,
      "has_wiki": false,
      "homepage": null,
      "languages": {
        "Java": 3451857
      },
      "pushed_at": "2026-07-25T07:19:01Z",
      "created_at": "2020-09-15T05:07:44Z",
      "owner_type": "Organization",
      "updated_at": "2026-07-25T07:19:04Z",
      "description": "OpenRewrite recipes that perform common Java testing migration tasks.",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": null,
      "default_branch": "main",
      "license_spdx_raw": "NOASSERTION",
      "primary_language": "Java",
      "significant_languages": [
        "Java"
      ]
    },
    "owner": {
      "blog": "https://docs.openrewrite.org",
      "name": "OpenRewrite",
      "type": "Organization",
      "login": "openrewrite",
      "company": null,
      "location": "San Francisco, CA",
      "followers": 984,
      "avatar_url": "https://avatars.githubusercontent.com/u/61478321?v=4",
      "created_at": "2020-02-25T21:27:36Z",
      "is_verified": null,
      "public_repos": 75,
      "account_age_days": 2341
    },
    "license": {
      "state": "custom",
      "spdx_id": null,
      "raw_spdx": "NOASSERTION",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v3.42.1",
          "kind": "patch",
          "published_at": "2026-07-20T14:04:34Z"
        },
        {
          "tag": "v3.42.0",
          "kind": "minor",
          "published_at": "2026-07-14T05:53:38Z"
        },
        {
          "tag": "v3.41.0",
          "kind": "minor",
          "published_at": "2026-07-01T06:17:41Z"
        },
        {
          "tag": "v3.40.0",
          "kind": "minor",
          "published_at": "2026-06-21T20:07:33Z"
        },
        {
          "tag": "v3.39.0",
          "kind": "minor",
          "published_at": "2026-06-19T13:58:30Z"
        },
        {
          "tag": "v3.38.0",
          "kind": "minor",
          "published_at": "2026-06-17T10:30:51Z"
        },
        {
          "tag": "v3.37.0",
          "kind": "minor",
          "published_at": "2026-06-03T14:24:35Z"
        },
        {
          "tag": "v3.36.0",
          "kind": "minor",
          "published_at": "2026-05-21T10:54:20Z"
        },
        {
          "tag": "v3.35.3",
          "kind": "patch",
          "published_at": "2026-05-07T07:24:44Z"
        },
        {
          "tag": "v3.35.2",
          "kind": "patch",
          "published_at": "2026-04-27T10:20:02Z"
        },
        {
          "tag": "v3.35.1",
          "kind": "patch",
          "published_at": "2026-04-23T11:10:22Z"
        },
        {
          "tag": "v3.35.0",
          "kind": "minor",
          "published_at": "2026-04-21T09:03:59Z"
        },
        {
          "tag": "v3.34.0",
          "kind": "minor",
          "published_at": "2026-04-08T13:23:21Z"
        },
        {
          "tag": "v3.33.0",
          "kind": "minor",
          "published_at": "2026-03-31T16:38:23Z"
        },
        {
          "tag": "v3.32.0",
          "kind": "minor",
          "published_at": "2026-03-27T16:16:12Z"
        },
        {
          "tag": "v3.31.0",
          "kind": "minor",
          "published_at": "2026-03-25T10:34:58Z"
        },
        {
          "tag": "v3.30.0",
          "kind": "minor",
          "published_at": "2026-03-12T14:44:02Z"
        },
        {
          "tag": "v3.29.0",
          "kind": "minor",
          "published_at": "2026-03-04T17:41:47Z"
        },
        {
          "tag": "v3.28.0",
          "kind": "minor",
          "published_at": "2026-02-25T13:13:05Z"
        },
        {
          "tag": "v3.27.0",
          "kind": "minor",
          "published_at": "2026-02-11T09:32:33Z"
        },
        {
          "tag": "v3.26.0",
          "kind": "minor",
          "published_at": "2026-01-20T19:51:12Z"
        },
        {
          "tag": "v3.25.0",
          "kind": "minor",
          "published_at": "2026-01-07T16:38:01Z"
        },
        {
          "tag": "v3.24.0",
          "kind": "minor",
          "published_at": "2025-12-16T16:59:41Z"
        },
        {
          "tag": "v3.23.0",
          "kind": "minor",
          "published_at": "2025-12-05T11:20:11Z"
        },
        {
          "tag": "v3.22.0",
          "kind": "minor",
          "published_at": "2025-11-20T12:20:32Z"
        },
        {
          "tag": "v3.21.3",
          "kind": "patch",
          "published_at": "2025-11-12T18:53:27Z"
        },
        {
          "tag": "v3.21.2",
          "kind": "patch",
          "published_at": "2025-11-05T14:39:14Z"
        },
        {
          "tag": "v3.21.1",
          "kind": "patch",
          "published_at": "2025-11-05T13:41:45Z"
        },
        {
          "tag": "v3.21.0",
          "kind": "minor",
          "published_at": "2025-11-04T15:13:50Z"
        },
        {
          "tag": "v3.20.0",
          "kind": "minor",
          "published_at": "2025-10-22T12:22:10Z"
        },
        {
          "tag": "v3.19.0",
          "kind": "minor",
          "published_at": "2025-10-10T17:54:11Z"
        },
        {
          "tag": "v3.18.0",
          "kind": "minor",
          "published_at": "2025-10-02T16:09:07Z"
        },
        {
          "tag": "v3.17.0",
          "kind": "minor",
          "published_at": "2025-09-24T13:03:02Z"
        },
        {
          "tag": "v3.16.3",
          "kind": "patch",
          "published_at": "2025-09-18T09:34:29Z"
        },
        {
          "tag": "v3.16.2",
          "kind": "patch",
          "published_at": "2025-09-10T11:24:08Z"
        },
        {
          "tag": "v3.16.1",
          "kind": "patch",
          "published_at": "2025-09-09T14:04:30Z"
        },
        {
          "tag": "v3.16.0",
          "kind": "minor",
          "published_at": "2025-08-27T16:34:56Z"
        },
        {
          "tag": "v3.15.1",
          "kind": "patch",
          "published_at": "2025-08-21T20:15:49Z"
        },
        {
          "tag": "v3.15.0",
          "kind": "minor",
          "published_at": "2025-08-12T21:32:47Z"
        },
        {
          "tag": "v3.14.1",
          "kind": "patch",
          "published_at": "2025-07-23T21:58:51Z"
        },
        {
          "tag": "v3.14.0",
          "kind": "minor",
          "published_at": "2025-07-23T11:29:38Z"
        },
        {
          "tag": "v3.13.0",
          "kind": "minor",
          "published_at": "2025-07-16T14:56:57Z"
        },
        {
          "tag": "v3.12.0",
          "kind": "minor",
          "published_at": "2025-07-09T15:52:55Z"
        },
        {
          "tag": "v3.11.0",
          "kind": "minor",
          "published_at": "2025-06-25T11:53:28Z"
        },
        {
          "tag": "v3.10.0",
          "kind": "minor",
          "published_at": "2025-05-28T16:04:22Z"
        },
        {
          "tag": "v3.9.0",
          "kind": "minor",
          "published_at": "2025-05-20T18:02:03Z"
        },
        {
          "tag": "v3.8.0",
          "kind": "minor",
          "published_at": "2025-05-07T17:52:59Z"
        },
        {
          "tag": "v3.7.0",
          "kind": "minor",
          "published_at": "2025-04-24T18:35:49Z"
        },
        {
          "tag": "v3.6.1",
          "kind": "patch",
          "published_at": "2025-04-10T15:50:09Z"
        },
        {
          "tag": "v3.6.0",
          "kind": "minor",
          "published_at": "2025-04-09T19:26:43Z"
        },
        {
          "tag": "v3.5.1",
          "kind": "patch",
          "published_at": "2025-03-27T19:38:38Z"
        },
        {
          "tag": "v3.5.0",
          "kind": "minor",
          "published_at": "2025-03-24T13:21:25Z"
        },
        {
          "tag": "v3.4.0",
          "kind": "minor",
          "published_at": "2025-03-11T20:36:12Z"
        },
        {
          "tag": "v3.3.0",
          "kind": "minor",
          "published_at": "2025-02-20T22:57:17Z"
        },
        {
          "tag": "v3.2.0",
          "kind": "minor",
          "published_at": "2025-02-07T17:30:25Z"
        },
        {
          "tag": "v3.1.0",
          "kind": "minor",
          "published_at": "2025-01-24T17:00:35Z"
        },
        {
          "tag": "v3.0.0",
          "kind": "major",
          "published_at": "2025-01-10T17:37:58Z"
        },
        {
          "tag": "v2.24.0",
          "kind": "minor",
          "published_at": "2024-12-18T15:40:21Z"
        },
        {
          "tag": "v2.23.1",
          "kind": "patch",
          "published_at": "2024-11-28T19:12:50Z"
        },
        {
          "tag": "v2.23.0",
          "kind": "minor",
          "published_at": "2024-11-27T16:39:19Z"
        },
        {
          "tag": "v2.22.0",
          "kind": "minor",
          "published_at": "2024-11-13T16:42:33Z"
        },
        {
          "tag": "v2.21.0",
          "kind": "minor",
          "published_at": "2024-10-23T15:38:47Z"
        },
        {
          "tag": "v2.20.1",
          "kind": "patch",
          "published_at": "2024-10-11T11:57:31Z"
        },
        {
          "tag": "v2.20.0",
          "kind": "minor",
          "published_at": "2024-10-10T09:02:11Z"
        },
        {
          "tag": "v2.19.0",
          "kind": "minor",
          "published_at": "2024-09-24T19:52:11Z"
        },
        {
          "tag": "v2.18.0",
          "kind": "minor",
          "published_at": "2024-09-11T18:27:14Z"
        },
        {
          "tag": "v2.17.1",
          "kind": "patch",
          "published_at": "2024-09-03T14:00:08Z"
        },
        {
          "tag": "v2.17.0",
          "kind": "minor",
          "published_at": "2024-08-28T14:37:31Z"
        },
        {
          "tag": "v2.16.0",
          "kind": "minor",
          "published_at": "2024-08-12T20:30:20Z"
        },
        {
          "tag": "v2.15.0",
          "kind": "minor",
          "published_at": "2024-07-31T12:57:06Z"
        },
        {
          "tag": "v2.14.1",
          "kind": "patch",
          "published_at": "2024-07-15T09:47:07Z"
        },
        {
          "tag": "v2.14.0",
          "kind": "minor",
          "published_at": "2024-07-11T12:47:36Z"
        },
        {
          "tag": "v2.13.0",
          "kind": "minor",
          "published_at": "2024-07-03T17:18:15Z"
        },
        {
          "tag": "v2.12.2",
          "kind": "patch",
          "published_at": "2024-06-19T18:57:40Z"
        },
        {
          "tag": "v2.12.1",
          "kind": "patch",
          "published_at": "2024-06-19T13:55:54Z"
        },
        {
          "tag": "v2.12.0",
          "kind": "minor",
          "published_at": "2024-06-19T09:46:22Z"
        },
        {
          "tag": "v2.11.0",
          "kind": "minor",
          "published_at": "2024-06-07T23:06:41Z"
        },
        {
          "tag": "v2.10.1",
          "kind": "patch",
          "published_at": "2024-05-22T22:16:50Z"
        },
        {
          "tag": "v2.10.0",
          "kind": "minor",
          "published_at": "2024-05-22T16:52:40Z"
        },
        {
          "tag": "v2.9.0",
          "kind": "minor",
          "published_at": "2024-05-18T06:28:46Z"
        },
        {
          "tag": "v2.8.0",
          "kind": "minor",
          "published_at": "2024-05-08T15:08:36Z"
        },
        {
          "tag": "v2.7.0",
          "kind": "minor",
          "published_at": "2024-04-24T15:41:36Z"
        },
        {
          "tag": "v2.6.0",
          "kind": "minor",
          "published_at": "2024-03-19T20:01:04Z"
        },
        {
          "tag": "v2.5.0",
          "kind": "minor",
          "published_at": "2024-03-12T22:20:42Z"
        },
        {
          "tag": "v2.4.1",
          "kind": "patch",
          "published_at": "2024-02-20T21:35:32Z"
        },
        {
          "tag": "v2.4.0",
          "kind": "minor",
          "published_at": "2024-02-20T20:42:37Z"
        },
        {
          "tag": "v2.3.2",
          "kind": "patch",
          "published_at": "2024-02-06T18:51:02Z"
        },
        {
          "tag": "v2.3.1",
          "kind": "patch",
          "published_at": "2024-01-23T18:50:58Z"
        },
        {
          "tag": "v2.3.0",
          "kind": "minor",
          "published_at": "2024-01-16T16:16:17Z"
        },
        {
          "tag": "v2.2.0",
          "kind": "minor",
          "published_at": "2024-01-09T16:58:21Z"
        },
        {
          "tag": "v2.1.5",
          "kind": "patch",
          "published_at": "2023-12-21T14:29:07Z"
        },
        {
          "tag": "v2.1.4",
          "kind": "patch",
          "published_at": "2023-12-08T13:50:00Z"
        },
        {
          "tag": "v2.1.3",
          "kind": "patch",
          "published_at": "2023-12-08T11:00:18Z"
        },
        {
          "tag": "v2.1.2",
          "kind": "patch",
          "published_at": "2023-12-04T20:56:59Z"
        },
        {
          "tag": "v2.1.1",
          "kind": "patch",
          "published_at": "2023-11-25T11:44:29Z"
        },
        {
          "tag": "v2.1.0",
          "kind": "minor",
          "published_at": "2023-11-11T01:36:42Z"
        },
        {
          "tag": "v2.0.13",
          "kind": "patch",
          "published_at": "2023-10-27T23:55:34Z"
        },
        {
          "tag": "v2.0.12",
          "kind": "patch",
          "published_at": "2023-10-03T03:01:59Z"
        },
        {
          "tag": "v2.0.11",
          "kind": "patch",
          "published_at": "2023-09-12T14:41:55Z"
        },
        {
          "tag": "v2.0.10",
          "kind": "patch",
          "published_at": "2023-08-24T20:23:11Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "c9ebc4f47b33d470bd739fa9930fd391df565112",
          "body": "…ng MockedStatic (#1060)\n\n* MockitoWhenOnStaticToMockStatic: name unnamed `_` variable when reusing MockedStatic\n\nWhen a `MockedStatic` was held in an unnamed variable\n(`try (var _ = Mockito.mockStatic(A.class))`), the recipe emitted\n`_.when(...)`, which does not compile. Rename the resource to a ge\n[…]\n on Java 25 with `rewrite-java-25` so unnamed `_` variables parse.\n\n* Add test for renaming multiple unnamed variables individually\n\n* Drop Java 25 build bump; to be handled in a separate migration PR",
          "is_bot": false,
          "headline": "MockitoWhenOnStaticToMockStatic: name unnamed `_` variable when reusi…",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-07-25T07:18:59Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "4534e081c149054069956237864dd6e3e81844b3",
          "body": "Swap the test parser from `rewrite-java-21` to `rewrite-java-25` and override\nthe toolchain to 25 (the `recipe-library` plugin pins it to 21), mirroring\nrewrite-migrate-java. CI now provisions JDK 25 and 21 via the shared workflow.\n\nThe three java-21 -> java-25 fallout failures (AssertToAssertions,\n\n[…]\nl caused by the\nparser dropping a method invocation's type when an argument type was\nunresolvable. That is now fixed upstream in openrewrite/rewrite#8318, so no\nrecipe or test changes are needed here.",
          "is_bot": false,
          "headline": "Build and test on Java 25 with rewrite-java-25 (#1061)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-07-25T07:07:08Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b1bbe20fc81f3ad8acf12577cb378607b6c0a50e",
          "body": "* HamcrestMatcherToJUnit5: support Kotlin via KotlinTemplate branches\n\n* Attribute Kotlin types after KotlinTemplate instead of relaxing validation\n\n* Explain immutableExecutionContext(false) in notEqualToKotlin test\n\n* Clarify why only Kotlin needs post-template type attribution\n\n* Remove Kotlin ty\n[…]\nng) vs assertX(condition, Supplier) overloads\nstay ambiguous when the reason is a substituted placeholder, leaving the call\nuntyped so the static import is dropped. Attribute just that enclosing call.",
          "is_bot": false,
          "headline": "HamcrestMatcherToJUnit5: support Kotlin sources (#1058)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-07-25T07:06:17Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8cfaee5af4b1d232b8b1e74802a33b9b89d30249",
          "body": "…n't be rendered (#1066)\n\nAnonymous and local class types (proper JavaType.Class, not JavaType.Unknown)\nrender an invalid declared type such as `MyTest.1 x = ...`, which makes the\nextraction template generate the wrong number of statements and crashes the run.\nThe #1059 guard only covered Unknown/None/Void/Null. Guard the template apply so\nany such failure leaves the argument inline instead of failing the recipe.",
          "is_bot": false,
          "headline": "Leave AssertThrowsOnLastStatement arguments inline when their type ca…",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-07-24T16:38:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "acfa18f0d12cf25273eb6e63425a5eae2fcd57c6",
          "body": "* refactor: extract shared TestNgAsserts.isFloatingPointType helper\n\n* feat: add TestNgAssertionToAssertJ assertEquals/assertNotEquals mapping\n\n* feat: cover boolean/null/same/noOrder/fail in TestNgAssertionToAssertJ\n\n* feat: remove dead local Assertion instance after rewriting its calls\n\n* feat: wi\n[…]\n contextSensitive and dead Supplier import\n\n* refactor: drop unnecessary contextSensitive and dead Supplier import in TestNgSoftAssertToAssertJ\n\n---------\n\nCo-authored-by: Tim te Beek <tim@moderne.io>",
          "is_bot": false,
          "headline": "Migrate TestNG Assertion (instance) to AssertJ (#1064)",
          "author_name": "Julien Herr",
          "author_login": "juherr",
          "committed_at": "2026-07-24T16:25:45Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5fe4cadeb3626da64c1b2246daf86411ef748697",
          "body": "…1065)\n\n* AssertTrueNullToAssertNull: support Kotlin via LST manipulation\n\nReplace the contextSensitive JavaTemplate, which generated 0 statements on a\nKotlin LST, with direct LST manipulation (rename to assertNull, rewrite the\nfirst argument, and fix the method type). This works on both Java and Ko\n[…]\ned an empty body on\nKotlin, throwing IndexOutOfBounds on getStatements().get(0). Leave the JUnit 4\n@Test(expected = ..., timeout = ...) intact on Kotlin rather than crashing or\ndropping the arguments.",
          "is_bot": false,
          "headline": "Support Kotlin in three JUnit testing recipes (fix crashes/no-ops) (#…",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-07-24T15:49:54Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d7134028d6323946e311772fa15255b1fcf4e93d",
          "body": "Add the `TestNgSoftAssertToAssertJ` recipe and wire it into the\n`TestNgToAssertj` declarative recipe so that TestNG soft assertions\n(`org.testng.asserts.SoftAssert`) are converted to AssertJ soft\nassertions (`org.assertj.core.api.SoftAssertions`).\n\nThe recipe rewrites the instance assertion calls\n(`\n[…]\nnAnyOrder).\n\nAlso broaden the assertj-core `onlyIfUsing` dependency trigger from\n`org.testng.*` to `org.testng..*` so classes using only\n`org.testng.asserts.SoftAssert` still get the dependency added.",
          "is_bot": false,
          "headline": "feat: migrate TestNG SoftAssert to AssertJ SoftAssertions (#1063)",
          "author_name": "Julien Herr",
          "author_login": "juherr",
          "committed_at": "2026-07-24T10:13:27Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "7ee9a16af02c36dbf459ea74241a2130f86076b4",
          "body": "RemoveNotMatcherVisitor was invoked via visit(tree, ctx), which roots the\nsub-visitor at Cursor.ROOT. When a not() matcher wraps a bare value instead\nof another Hamcrest matcher, the visitor wraps it in equalTo() and calls\nmaybeAddImport, whose ImportService lookup walks the cursor for an enclosing\n\n[…]\nceFile parent found\". Pass the current\ncursor as the parent so the sub-visitor inherits a path with the\nJavaSourceFile ancestor. Applied to both HamcrestMatcherToJUnit5 and\nHamcrestInstanceOfToJUnit5.",
          "is_bot": false,
          "headline": "Fix Hamcrest not() unwrap crash when wrapping a bare value (#1062)",
          "author_name": "Jammy Louie",
          "author_login": "Jammy-Louie",
          "committed_at": "2026-07-23T22:30:42Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5a35eafd825d264777056d47fdca1d016065c86b",
          "body": "…(#1057)",
          "is_bot": false,
          "headline": "AssertTrueNegationToAssertFalse: support Kotlin via LST manipulation …",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-07-23T15:57:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c56011d863784b1bc114d70280a33b7a9d357c63",
          "body": "…(#1059)\n\nExtracting a last-statement argument whose type is `None`, `Unknown`,\n`void` or `null` rendered an invalid variable declaration (an empty type\nproduced a `J.Assignment`, causing `J$Assignment cannot be cast to\nJ$VariableDeclarations`; `void`/`<unknown>` produced templates that\ngenerated no statements). Such types occur when the `assertThrows` lambda\nwas just synthesized earlier in the same run (e.g. from `@Test(expected)`).\nLeave those arguments inline instead of extracting them.",
          "is_bot": false,
          "headline": "Fix AssertThrowsOnLastStatement crash on unattributed argument types …",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-07-23T15:45:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "acb0b002114224e56c8cea7f37b041e40cadb64c",
          "body": null,
          "is_bot": false,
          "headline": "Set Develocity `projectId` to \"openrewrite\" (#1056)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-07-22T15:05:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "81d6e6708db98ddf38639a0c9ff21b865fe4228e",
          "body": "Co-authored-by: Moderne <team@moderne.io>",
          "is_bot": false,
          "headline": "Move Develocity to community.develocity.cloud",
          "author_name": "tim@moderne.io",
          "author_login": "timtebeek",
          "committed_at": "2026-07-22T12:14:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cefa93583d858576e8a30bfa947158f0933b349c",
          "body": "Co-authored-by: Moderne <team@moderne.io>",
          "is_bot": false,
          "headline": "OpenRewrite recipe best practices",
          "author_name": "timtebeek@gmail.com",
          "author_login": "timtebeek",
          "committed_at": "2026-07-22T09:40:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cdad6240d97dac27787786adbcd4a45ec7b2588e",
          "body": "… (#1055)\n\nApplying the recipe to Kotlin test sources threw\n\"Expected a template that would generate exactly one statement to\nreplace one statement, but generated 0\" because Java statement\ntemplates produce no statements on a Kotlin LST.\n\nBranch on K.CompilationUnit at each template site:\n- private \n[…]\nch template apply.\nClass-wide autoformat is skipped for Kotlin sources since it would\nreformat unrelated code across the whole class.\n\nFixes https://github.com/moderneinc/customer-requests/issues/2825",
          "is_bot": false,
          "headline": "ReplaceInitMockToOpenMock: support Kotlin via KotlinTemplate branches…",
          "author_name": "Merlin Bögershausen",
          "author_login": "MBoegers",
          "committed_at": "2026-07-21T12:36:31Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f0f55abf1414ab1f3dd44ab5fa2b2ffffcd24d65",
          "body": "* Fix infinite loop unwrapping non-Matchers not() in Hamcrest JUnit5 recipes\n\n* Migrate CoreMatchers not()/instanceOf()/isA() in Hamcrest JUnit5 recipes",
          "is_bot": false,
          "headline": "Fix Hamcrest not() unwrap infinite loop and support CoreMatchers (#1054)",
          "author_name": "Jammy Louie",
          "author_login": "Jammy-Louie",
          "committed_at": "2026-07-20T13:37:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fa03dcc06b84f89411e0b358c64dd3ac659092bf",
          "body": "Co-authored-by: Moderne <team@moderne.io>",
          "is_bot": false,
          "headline": "OpenRewrite recipe best practices",
          "author_name": "timtebeek@gmail.com",
          "author_login": "timtebeek",
          "committed_at": "2026-07-20T09:21:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "224c5ebb42ea181c2579f7047e4cd3130a29669f",
          "body": "…053)\n\n* AssertEqualsNullToAssertNull: support Kotlin via LST manipulation\n\n* AssertEqualsNullToAssertNull: simplify argument rewrite via ListUtils\n\n* AssertEqualsNullToAssertNull: drop redundant method type null check",
          "is_bot": false,
          "headline": "AssertEqualsNullToAssertNull: support Kotlin via LST manipulation (#1…",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-07-17T10:49:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cc1032964e35f82c5ba98e9340c40b2294160c0e",
          "body": "TEST_ANNOTATION_PATTERN's `*Test*` segment matches any simple\nannotation name containing \"Test\", which incidentally also matches\n`@TestFactory`. Unlike `@Test`/`@ParameterizedTest`/`@RepeatedTest`/\n`@TestTemplate`, `@TestFactory` methods are required by JUnit Jupiter\nto return a value (e.g. `Collect\n[…]\n their\nreturn type to `Unit` produces a Kotlin type-mismatch compile error.\n\nAdd an explicit exclusion for `@TestFactory` and a regression test.\n\nCo-authored-by: Neil Mushell <neil.mushell@airbnb.com>",
          "is_bot": false,
          "headline": "KotlinTestMethodsShouldReturnUnit: exclude @TestFactory methods (#1052)",
          "author_name": "neil-mushell",
          "author_login": "neil-mushell",
          "committed_at": "2026-07-14T21:58:20Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2b5d8526dc226ff4794716133b2d0780eb257530",
          "body": "…builds\n\nDrop `newVersion: 3.x` from the `mockito-all` -> `mockito-core`\n`ChangeDependency` step. For a version managed by a parent POM,\n`ChangeDependency` did not see the child inherit the renamed\n`mockito-core` management within the same run, so it hardcoded an\nexplicit version onto the child depe\n[…]\n3.x` bumps\nthe version. Managed child dependencies stay versionless and the recipe\nconverges in a single cycle, matching the `mockito-inline` -> `mockito-core`\npattern already used in Mockito4to5Only.",
          "is_bot": false,
          "headline": "Keep Mockito dependency managed in Mockito1to3Migration multi-module …",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-07-13T08:10:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e2dffcaf7ea1486cc10c23e5a45444fec5ab453f",
          "body": "Co-authored-by: Moderne <team@moderne.io>",
          "is_bot": false,
          "headline": "OpenRewrite recipe best practices",
          "author_name": "timtebeek@gmail.com",
          "author_login": "timtebeek",
          "committed_at": "2026-07-13T07:45:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c709cec39a30ef12990715b5d96501604f16ade9",
          "body": "With openrewrite/rewrite#8229, a plain '17' is canonicalized to '[17,)'\nby HasMinimumJavaVersion, so the explicit range wrapper is no longer\nnecessary and the shorter form matches how a reader would expect the\noption to be written.",
          "is_bot": false,
          "headline": "Simplify JUnit5to6Migration minimum Java version to '17' (#1050)",
          "author_name": "Steve Elliott",
          "author_login": "steve-aom-elliott",
          "committed_at": "2026-07-10T15:26:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d3830c04a67edd51b3d9784c6429dfab7997b356",
          "body": "…#1049)\n\nA bare version like '17' is parsed as an exact-match selector by\nSemver, so the precondition returns false on repos declaring a higher\nJava version (e.g. 21) and the whole recipe is silently skipped.\nSwitching to '[17,)' makes the intent match the recipe's name.",
          "is_bot": false,
          "headline": "Use range selector so JUnit5to6Migration gates on Java 17 or higher (…",
          "author_name": "Steve Elliott",
          "author_login": "steve-aom-elliott",
          "committed_at": "2026-07-10T13:29:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b0b1f19daed5e26989059ed4b49edb2a43e3dd6c",
          "body": "`AssertThrowsOnLastStatement` is a `JavaTemplate`-based recipe, and Java\nvisitors also run over Kotlin because `K.CompilationUnit` implements\n`JavaSourceFile`. On a Kotlin file the recipe emitted Java syntax for the\nextracted variable declaration, producing invalid code such as\n`baz: String = baz()`\n[…]\ntrailing call would wrap it as an expression\n(`var o = ...`) and fail to parse.\n\nGroovy and other languages remain excluded via `isAcceptable`.\n\nCo-authored-by: Claude Opus 4.8 <noreply@anthropic.com>",
          "is_bot": false,
          "headline": "Support Kotlin sources in `AssertThrowsOnLastStatement` (#1048)",
          "author_name": "Vladimir Sitnikov",
          "author_login": "vlsi",
          "committed_at": "2026-07-10T13:17:38Z",
          "body_truncated": true,
          "is_coding_agent": true
        },
        {
          "oid": "2e6d48581b900086309249b4fbd62c25d6764cb9",
          "body": "Co-authored-by: Moderne <team@moderne.io>",
          "is_bot": false,
          "headline": "OpenRewrite recipe best practices",
          "author_name": "tim@moderne.io",
          "author_login": "timtebeek",
          "committed_at": "2026-07-03T08:57:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "95ff73ab69a3ee2e0be0311b77f94a0179e54c41",
          "body": "… incomplete (#1047)",
          "is_bot": false,
          "headline": "Keep `mockStatic` import in `CleanupMockitoImports` when type info is…",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-06-23T07:48:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cba9383053f52d6d58f7af0201ff2a1da5cff673",
          "body": "Use this link to re-run the recipe: https://app.moderne.io/builder/yESIGzVB0?organizationId=QUxML01vZGVybmUgKyBPcGVuUmV3cml0ZQ%3D%3D\n\nCo-authored-by: Moderne <team@moderne.io>",
          "is_bot": false,
          "headline": "Recipe best practices",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-06-23T07:38:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9321cbc3968dd4974ce0bcbfe5eebfa04d9202f6",
          "body": "* Convert `assertThrows` with an `Executable` variable, retyping to `ThrowingCallable`\n\nFixes #511\n\n* Address review: inline safe via reduce; drop unused import; hoist ThrowingCallable type",
          "is_bot": false,
          "headline": "Convert `assertThrows` with an `Executable` variable (#1046)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-06-20T16:38:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0eb4765dce528e4076e2f2faf5b616bd672700d4",
          "body": "…sent (#1043)\n\nWhen a method carries both a JUnit 4 lifecycle annotation (e.g. @Before)\nand its Jupiter equivalent (@BeforeEach), changing the type of the JUnit 4\nannotation produced a duplicate, non-repeatable annotation. Remove the\nJUnit 4 annotation instead in that case.\n\nFixes #501",
          "is_bot": false,
          "headline": "Skip JUnit 4 lifecycle annotation when Jupiter equivalent already pre…",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-06-20T16:17:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e4715700c44fda54f76a32c73b18c093d9ef84aa",
          "body": "* Add DecomposeConjunctionAssertion recipe for issue #387\n\n* Add end-to-end issue #387 tests for conjunction decomposition\n\n* Use built-in Expression.unwrap() instead of a custom helper\n\n* Add test showing same-subject conjuncts collapse into a chain\n\n* Flatten conjuncts functionally with ListUtils.flatMap\n\n* Build decomposed assertions with ListUtils.flatMap",
          "is_bot": false,
          "headline": "Decompose `assertThat(a && b).isTrue()` into separate assertions (#1042)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-06-20T15:45:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8ade02dcc506c6f7caf6805769ae41e95a8639c0",
          "body": "…1041)\n\nRewrites second-based @Timeout values at or above a configurable\nthreshold (default 1000s) to the equivalent minutes, e.g.\n@Timeout(10000) -> @Timeout(value = 167, unit = TimeUnit.MINUTES),\nmaking likely millisecond mistakes visible. Implements option a) of #452\nand adds it to JupiterBestPractices.\n\nFixes #452",
          "is_bot": false,
          "headline": "Add recipe to surface implausible JUnit @Timeout values as minutes (#…",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-06-20T14:39:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7e27ad6a6934642e7baae33aa0d734e67733be2a",
          "body": "Resolve #308 so that classes whose methods carry a custom annotation\nthat is itself meta-annotated with @Test (e.g. @MavenTest) also have\ntheir redundant public modifier removed.\n\nUse AnnotationMatcher's built-in meta-annotation matching rather than\nhand-rolled recursion.",
          "is_bot": false,
          "headline": "TestsShouldNotBePublic: recognize meta-annotated test methods (#1040)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-06-20T14:28:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "db78ffdbc2bbf64aa55c7646c3603f7d34765586",
          "body": "…compareTo (#1039)\n\n* Cover previously-commented AssertJ best-practice tests\n\nUn-comments the disabled cases in AssertJBestPracticesTest and closes the\ncoverage gaps they represented:\n\n- Comparable relational operators (>, >=, <, <=) were already handled by\n  AssertJPrimitiveRules; the cases were on\n[…]\nth object\n  and primitive arrays. Ordered before AssertJNumberRules to avoid the\n  `isGreaterThanOrEqualTo(1)` -> `isPositive()` collision.\n\n* Update recipes.csv for new recipe and declarative entries",
          "is_bot": false,
          "headline": "Cover commented AssertJ tests: array length, Comparable & BigDecimal …",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-06-20T14:01:38Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9a8b7cb872efbe08a0cfdd2e38d4f124c8f98c3c",
          "body": "* Add SimplifyAssertJNullRelatedAssertion to fix isSameAs(null) compile error\n\nassertThat(null == a).isEqualTo(true) was converted by the picnic\nAssertJObjectRulesRecipes into the uncompilable assertThat(null).isSameAs(a),\nsince the Refaster rule binds the left operand as the actual value.\n\nThis add\n[…]\nJInstanceOfAssertion. Only comparisons against the\nnull literal are handled; genuine x == y still becomes isSameAs(y).\n\nFixes #868\n\n* Use J.Literal.isLiteralValue(expr, null) instead of a local helper",
          "is_bot": false,
          "headline": "Fix isSameAs(null) compile error from null reference comparisons (#1038)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-06-20T13:29:37Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9e69b1bb2cb4e624b502b6888cf6484cbb5183b8",
          "body": "The existing rule targeted java.util.Collection, so an actual typed as\nthe broader java.lang.Iterable was not matched. Widen the required type\nto java.lang.Iterable, which subsumes the Collection case.\n\nFixes #811",
          "is_bot": false,
          "headline": "Simplify AssertJ hasSize(0) to isEmpty() for Iterable (#1037)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-06-20T12:42:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cd8b263729a342b628a4168de887ad1e3fd7f3eb",
          "body": "…in a single run (#1036)\n\nThe Assertj aggregate normalizes primitive isSameAs/isNotSameAs to\nisEqualTo/isNotEqualTo via Picnic's AssertJPrimitiveRulesRecipes, after\nwhich our type-specific rules collapse isEqualTo(0) to isZero(), etc.\nBecause between-cycle re-attribution does not give the rewritten \n[…]\nso match the isSameAs/isNotSameAs forms directly so\nthey collapse straight to isZero/isNotZero/isOne, and order them before\nAssertJPrimitiveRulesRecipes so they win within a single cycle.\n\nFixes #1032",
          "is_bot": false,
          "headline": "Converge AssertJ isSameAs/isNotSameAs(0|1) to isZero/isNotZero/isOne …",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-06-20T12:21:44Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "286a3d7dea0605274987b21def46d1c80320ba6c",
          "body": "…stanceOf(Type.class) (#1035)\n\n* Add SimplifyAssertJInstanceOfAssertion recipe\n\nConvert `assertThat(x instanceof Type).isTrue()` to the dedicated\n`assertThat(x).isInstanceOf(Type.class)` (and `.isFalse()` / negated\nforms to `isNotInstanceOf`), so failures describe the actual type\ninstead of just \"ex\n[…]\nd and\nstatically imported `assertThat`, array types, and skips Java 16+\npattern bindings whose variable may be used later.\n\nFixes #1030\n\n* Regenerate recipes.csv for SimplifyAssertJInstanceOfAssertion",
          "is_bot": false,
          "headline": "Refactor assertThat(x instanceof Type).isTrue() to assertThat(x).isIn…",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-06-20T12:05:57Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9a16f5707d93a6a0cbe04b5ef7ea3ccd4abf0ee8",
          "body": "Handles literal-first AssertJ size assertions where the meaningful\nexpression sits on the isEqualTo(...) side, e.g.\nassertThat(4).isEqualTo(coll.size()) -> assertThat(coll).hasSize(4).\n\nThis is the always-safe \"Case A\" from the issue: the comparison is on a\nprimitive int (size()/length()/array length), so reversing the\nassertion is behavior-preserving. Object-equality reversal (Case B) is\nintentionally left untouched since it depends on equals() symmetry.\n\nFixes #1031",
          "is_bot": false,
          "headline": "Add SimplifyHasSizeFromIsEqualToAssertion recipe (#1034)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-06-20T11:58:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "54f3db8e472f9bd37dccd030fc1671b3f9728ad2",
          "body": "Normalize the AssertJ entry points introduced by TestNgToAssertj to a\nstatic import via UseStaticImport, so qualified Assert.assertX(...) calls\nbecome static-imported assertThat(...) instead of mirroring the source\nqualification as Assertions.assertThat(...).\n\nFixes #1029",
          "is_bot": false,
          "headline": "TestNgToAssertj: emit a static import for assertThat (#1033)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-06-20T11:56:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a8a3615d8a91364d50826349f535f128af26394f",
          "body": "…#1016)\n\nWires org.openrewrite.java.AddCommentToMethodInvocations into\nReplacePowerMockito after the Whitebox migration and before the PowerMock\ndependency removal, matching `org.powermock.reflect.Whitebox *(..)`. Any\nremaining Whitebox call with no faithful reflection equivalent (type-based\nget/set\n[…]\nn a bespoke one. Adds an\nend-to-end ReplacePowerMockitoIntegrationTest case (with powermock-reflect-1\non the classpath) proving migrate-and-flag together.\n\nCo-authored-by: Tim te Beek <tim@moderne.io>",
          "is_bot": false,
          "headline": "Flag un-migratable PowerMock powermock-reflect usage with a comment (…",
          "author_name": "Merlin Bögershausen",
          "author_login": "MBoegers",
          "committed_at": "2026-06-19T13:37:24Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "665bd845b0491b6dc8b08d4fd46bddd4385caeda",
          "body": "* Expand TestNG to AssertJ assertion coverage\n\nAdd dedicated recipes for assertSame/assertNotSame, assertThrows/expectThrows,\nassertEqualsNoOrder, and assertEqualsDeep/assertNotEqualsDeep, and fix\nassertEquals/assertNotEquals to use element-wise assertions (containsExactly,\ncontainsExactlyElementsOf\n[…]\nare still\nvisited and migrated. Brings the TestNG recipes and JUnitFailToAssertJFail\nin line with the recursing pattern already used elsewhere.\n\n---------\n\nCo-authored-by: Tim te Beek <tim@moderne.io>",
          "is_bot": false,
          "headline": "Expand TestNG to AssertJ assertion coverage (#1028)",
          "author_name": "Julien Herr",
          "author_login": "juherr",
          "committed_at": "2026-06-19T12:53:31Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b700d7b216ad689accdf2a8a69b290724d685cd0",
          "body": "Whitebox.invokeConstructor(Class, args...) -> Constructor lookup +\nnewInstance() on the named class:\n\n    Constructor<MyService> c = MyService.class.getDeclaredConstructor(String.class);\n    c.setAccessible(true);\n    MyService s = c.newInstance(\"Alice\");\n\nHandles both the Object... varargs overload\n[…]\ncomposite.\n\nReuses the base hasArrayArg helper; the constructor resolution and class-literal\nhelpers are kept private to the recipe, matching the existing InvokeMethod\nrecipe (no shared-base changes).",
          "is_bot": false,
          "headline": "Add PowerMockWhiteboxInvokeConstructorToJavaReflection recipe (#1027)",
          "author_name": "Merlin Bögershausen",
          "author_login": "MBoegers",
          "committed_at": "2026-06-18T16:17:14Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "20880b9e1a7a9c30b4d74587e4bd65a0cc9daa46",
          "body": null,
          "is_bot": false,
          "headline": "Add PowerMockWhiteboxGetMethodToJavaReflection recipe (#1026)",
          "author_name": "Merlin Bögershausen",
          "author_login": "MBoegers",
          "committed_at": "2026-06-18T15:32:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "97acbeedf12110585e8cc7838ccce46bef0af814",
          "body": "Parsing the useJUnitPlatform() snippet spins up the Groovy compiler and\nresolves the Gradle classpath on every call, even though the result\ndepends only on whether `.configureEach` is used. Cache the parsed\ntemplate on the run-scoped ExecutionContext so the parse happens once per\nrun instead of once per modified build script, and hand back a copy with\nfresh ids on each use to keep tree ids unique.",
          "is_bot": false,
          "headline": "Cache parsed Gradle template in GradleUseJunitJupiter",
          "author_name": "Knut Wannheden",
          "author_login": "knutwannheden",
          "committed_at": "2026-06-18T06:26:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5e4e776179bd62670aa6a9f34ca3d52fa5b7f63b",
          "body": "Use this link to re-run the recipe: https://app.moderne.io/recipes/org.openrewrite.xml.security.RemoveOwaspSuppressions?organizationId=QUxML01vZGVybmUgKyBPcGVuUmV3cml0ZQ%3D%3D#defaults=W3sidmFsdWUiOiIyMDI2LTA2LTE3IiwibmFtZSI6ImN1dE9mZkRhdGUifV0=\n\nCo-authored-by: Moderne <team@moderne.io>",
          "is_bot": false,
          "headline": "Remove out-of-date OWASP suppressions",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-06-17T17:37:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "96f93ccae5e88e21ff871d4841aca506d57953c2",
          "body": "Whitebox.getField(Class, \"name\") returns a reflective Field; migrate it to\nClass.getDeclaredField(\"name\") + setAccessible(true), reusing the result\nvariable as the local. Registered in the PowerMockWhiteboxToJavaReflection\ncomposite.\n\nA shared resultLocalName helper (reuse the declared result variable when the\ncall's result IS the reflective object) is added to WhiteboxToReflectionVisitor.",
          "is_bot": false,
          "headline": "Add PowerMockWhiteboxGetFieldToJavaReflection recipe (#1025)",
          "author_name": "Merlin Bögershausen",
          "author_login": "MBoegers",
          "committed_at": "2026-06-17T10:35:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "862bd49266051972948d6ad84e29ab150d31a4de",
          "body": "…ion (#1024)\n\nField.get and Method.invoke return Object, so a primitive-typed result\ndeclaration emitted a `(int) object` cast, which does not compile. Cast\nto the wrapper type instead; the surrounding assignment auto-unboxes.",
          "is_bot": false,
          "headline": "Box primitive casts in Whitebox getInternalState/invokeMethod reflect…",
          "author_name": "Merlin Bögershausen",
          "author_login": "MBoegers",
          "committed_at": "2026-06-17T07:01:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9e86af9ea65f776ede1cfe3f0dd431f50acce57a",
          "body": "…021)",
          "is_bot": false,
          "headline": "Refactor `PowerMockWhiteboxToJavaReflection` into per-API recipes (#1…",
          "author_name": "Merlin Bögershausen",
          "author_login": "MBoegers",
          "committed_at": "2026-06-17T05:54:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "30c392dc5a2b6d7eca5e5fbc6051b2fa4db231c7",
          "body": "…(#1023)\n\nThe where-overload supplies the declaring class to look the field up on.\ngetDeclaredField does not walk the class hierarchy, so for an inherited\nfield child.getClass().getDeclaredField(\"name\") throws NoSuchFieldException;\nonly Parent.class.getDeclaredField(\"name\") resolves it.\n\nGenerate th\n[…]\nything else\n(setAccessible, field.set, throws Exception, Field import) is identical to\nthe existing 3-arg path. The Class-typed placeholder also accepts a\nnon-literal Class<?> variable as the 4th arg.",
          "is_bot": false,
          "headline": "Support 4-arg Whitebox.setInternalState(target, field, value, Class) …",
          "author_name": "Merlin Bögershausen",
          "author_login": "MBoegers",
          "committed_at": "2026-06-16T16:47:53Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c9cd3bd9cb61feb433e31d1537a175130e296521",
          "body": "…t (#1022)\n\nUsesType matches against fully qualified type names, but the precondition was\ngiven the two-token \"org..* *Test*\" pattern that AnnotationMatcher uses. That\nonly ever matched because of a TypeNameMatcher bug where a ..* token followed by\na suffix matched every name, fixed upstream in #8012. Use a valid single-token\nglob org.junit..*Test* for the UsesType precondition; the AnnotationMatcher\npattern is unchanged.",
          "is_bot": false,
          "headline": "Fix UsesType precondition pattern in KotlinTestMethodsShouldReturnUni…",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-06-16T12:19:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a602b445dae2fc1f5e11f11fdf17980f324ce016",
          "body": "Use this link to re-run the recipe: https://app.moderne.io/builder/abtSSjvHK?organizationId=QUxML01vZGVybmUgKyBPcGVuUmV3cml0ZQ%3D%3D\n\nCo-authored-by: Moderne <team@moderne.io>",
          "is_bot": false,
          "headline": "OpenRewrite recipe best practices",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-06-16T10:56:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ff368ff6414b25a8dd1025ed3f233ec0ca5a2ebb",
          "body": "…ange (#1020)",
          "is_bot": false,
          "headline": "Update UpdateMockWebServerMockResponse test for nested-type render ch…",
          "author_name": "Steve Elliott",
          "author_login": "steve-aom-elliott",
          "committed_at": "2026-06-15T16:36:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "45342dcf77b3fe244b7728afe49802773b44258d",
          "body": "Disabled in d1e6bbba after teardown was injected in the wrong scope for\n@Nested classes; #742 fixed nested-class and qualified-class-name\nhandling. Re-enabling now that the underlying issue is resolved.",
          "is_bot": false,
          "headline": "Re-include CloseUnclosedStaticMocks in Mockito1to4Migration (#1019)",
          "author_name": "Steve Elliott",
          "author_login": "steve-aom-elliott",
          "committed_at": "2026-06-15T16:17:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e1cb892576518def734591baa3eb3de152b9b792",
          "body": "…n Testcontainers 2.x (#1014)\n\nTestcontainers 2.x removed the nested `LocalStackContainer.Service` enum and `getEndpointOverride(...)`. The existing `Testcontainers2Migration` only renamed the type, leaving `LocalStackContainer.Service.SQS` and `getEndpointOverride(...)` as unresolved references (Ja\n[…]\n alike).\n\nAdd a `Testcontainers2LocalStack` step (run before the type rename) that replaces `Service` constants with their service-name strings and `getEndpointOverride(service)` with `getEndpoint()`.",
          "is_bot": false,
          "headline": "Migrate removed LocalStack `Service` enum and `getEndpointOverride` i…",
          "author_name": "Merlin Bögershausen",
          "author_login": "MBoegers",
          "committed_at": "2026-06-12T09:28:55Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3934d1e33f7f66a699eda99c17fbe87451451d2b",
          "body": "…ing JUnit 6 migration (#1018)",
          "is_bot": false,
          "headline": "Add junit-platform-launcher testRuntimeOnly dependency for Gradle dur…",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-06-11T08:02:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d5554a9716c10230c4a8465c425d6b6075e46c5e",
          "body": "* Don't add MockitoExtension during migration when unsafe (#875)\n\n`AddMockitoExtensionIfAnnotationsUsed` was adding `@ExtendWith(MockitoExtension.class)`\neven when Mockito support was already provided another way, breaking tests.\n\n- Remove `AddMockitoExtensionIfAnnotationsUsed` and its companion\n  `\n[…]\nn checks.\n\n* Use J.ClassDeclaration#hasModifier for the abstract check\n\n* Use org.mockito.* wildcard for the Mockito-annotation checks\n\n* Use org.mockito.* wildcard in PowerMockRunnerDelegateToRunWith",
          "is_bot": false,
          "headline": "Don't add MockitoExtension during migration when unsafe (#875) (#1017)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-06-10T11:05:29Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6dc35d44f851b8bf7252e086ce4ddf6c8e761c4a",
          "body": "Use this link to re-run the recipe: https://app.moderne.io/recipes/org.openrewrite.AddToGitignore?organizationId=QUxML01vZGVybmUgKyBPcGVuUmV3cml0ZQ%3D%3D#defaults=W3sidmFsdWUiOiIuY29udGV4dC8iLCJuYW1lIjoiZW50cmllcyJ9XQ==\n\nCo-authored-by: Moderne <team@moderne.io>",
          "is_bot": false,
          "headline": "git-ignore .context/",
          "author_name": "Greg Oledzki",
          "author_login": "greg-at-moderne",
          "committed_at": "2026-06-09T11:31:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5b719c203a9206859e4b7e9456ec5503897cd121",
          "body": "Use this link to re-run the recipe: https://app.moderne.io/recipes/org.openrewrite.java.recipes.ExamplesExtractor?organizationId=QUxML01vZGVybmUgKyBPcGVuUmV3cml0ZQ%3D%3D\n\nCo-authored-by: Moderne <team@moderne.io>",
          "is_bot": false,
          "headline": "Extract documentation examples from tests",
          "author_name": "Greg Oledzki",
          "author_login": "greg-at-moderne",
          "committed_at": "2026-06-03T12:30:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1ca62235d5c5d13b5929374dad5a3ff4fd702a12",
          "body": null,
          "is_bot": false,
          "headline": "Match MockWebServer.shutdown() against pre-rename type (#1012)",
          "author_name": "Steve Elliott",
          "author_login": "steve-aom-elliott",
          "committed_at": "2026-06-02T19:43:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "947998830d5ca8e041472a3e7b1d0ee75c12c047",
          "body": "…ed from parent pom (#1011)",
          "is_bot": false,
          "headline": "Add direct mockwebserver3 dep when only old mockwebserver dep inherit…",
          "author_name": "Steve Elliott",
          "author_login": "steve-aom-elliott",
          "committed_at": "2026-06-02T15:52:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4d31fbb472e259a0bc8c7901654a63e9b1692428",
          "body": "…tions (#1010)\n\nAssertJ deprecated `AssertionsForClassTypes` and `AssertionsForInterfaceTypes`\nin favor of the unified `Assertions` entry point (assertj/assertj#4268).\n\nThis adds `MigrateAssertionsForClassAndInterfaceTypes`, which retargets all\nstatic methods of both classes to `Assertions`. The gen\n[…]\nrable`/... argument to e.g. `IterableAssert`\nand stop compiling. The new type-aware `MigrateAssertionsForClassTypes` recipe\nroutes only those colliding arguments to `assertThatObject`, resolving #664.",
          "is_bot": false,
          "headline": "Add recipe to migrate AssertionsForClassTypes/InterfaceTypes to Asser…",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-06-01T08:20:00Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "7cbff2a3ef15e4bd2ca3bcbb8f7d8b4554b36763",
          "body": "Use this link to re-run the recipe: https://app.moderne.io/recipes/org.openrewrite.recipes.rewrite.OpenRewriteRecipeBestPractices?organizationId=QUxML01vZGVybmUgKyBPcGVuUmV3cml0ZQ%3D%3D\n\nCo-authored-by: Moderne <team@moderne.io>",
          "is_bot": false,
          "headline": "OpenRewrite recipe best practices",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-05-29T08:57:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "86f2308c5646fbbd789458a81b15903165779a0a",
          "body": "…lable code (#1009)\n\n* fix: retain doNothing() stubs inside lambda bodies to prevent uncompilable empty lambda body\n\n* fix: retain doNothing() stubs in expression lambda and switch expression arms to prevent uncompilable code\n\n* Update src/main/java/org/openrewrite/java/testing/mockito/RemoveDoNothi\n[…]\nSwitchExpressionArm() into the single call site and removes the unnecessary mi != null check.\n\n---------\n\nCo-authored-by: Tim te Beek <tim@moderne.io>\nCo-authored-by: Tim te Beek <timtebeek@gmail.com>",
          "is_bot": false,
          "headline": "fix: retain doNothing() stubs inside lambda bodies to prevent uncompi…",
          "author_name": "darrencilia",
          "author_login": "darrencilia",
          "committed_at": "2026-05-28T22:18:24Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "45d25287c16359548f1e24b24a4e3775bc5535a0",
          "body": "Use this link to re-run the recipe: https://app.moderne.io/recipes/org.openrewrite.gradle.UpdateGradleWrapper?organizationId=QUxML01vZGVybmUgKyBPcGVuUmV3cml0ZS9PcGVuUmV3cml0ZQ%3D%3D#defaults=W3sidmFsdWUiOiI5LjUuMSIsIm5hbWUiOiJ2ZXJzaW9uIn0seyJ2YWx1ZSI6ImJpbiIsIm5hbWUiOiJkaXN0cmlidXRpb24ifSx7InZhbHVlIjoiYmFmYzE0MWI2MTlhZDYzNTBmZDk3NWZjOTAzMTU2ZGQ1YzE1MTk5OGNjOGIwNThlOGMxMDQ0YWI1ZjdiMDMxZiIsIm5hbWUiOiJkaXN0cmlidXRpb25DaGVja3N1bSJ9XQ==\n\nCo-authored-by: Moderne <team@moderne.io>",
          "is_bot": false,
          "headline": "Update Gradle wrapper 9.5.1",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-05-28T19:57:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a632e17c18f3c9c434c3a5066790db79d33b6321",
          "body": null,
          "is_bot": false,
          "headline": "Regenerate recipes.csv (#1007)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-05-28T18:36:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0b192ca3ca2509163516c0db32ef65a9bd80106a",
          "body": "* Add RemoveJupiterMigrationSupport recipe\n\n* Include RemoveJupiterMigrationSupport in JupiterBestPractices\n\n---------\n\nCo-authored-by: Tim te Beek <tim@moderne.io>",
          "is_bot": false,
          "headline": "Add RemoveJupiterMigrationSupport recipe (#1006)",
          "author_name": "sullis",
          "author_login": "sullis",
          "committed_at": "2026-05-26T08:22:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f3f61a6e10ac3e2a334d6a9832455a5fbbf7d872",
          "body": "* Reuse `MockedStatic` for consecutive stubbings of the same class\n\nFixes #1004: `MockitoWhenOnStaticToMockStatic` created nested\n`try (MockedStatic<X>)` blocks for sibling `Mockito.when()` calls on\nthe same static class, which Mockito 5 rejects at runtime with\n\"static mocking is already registered in the current thread\".\n\nSubsequent same-class stubbings (siblings or nested in inner blocks)\nnow share the enclosing `MockedStatic`.\n\n* Inline single-arg overload",
          "is_bot": false,
          "headline": "Reuse `MockedStatic` for consecutive stubbings of the same class (#1005)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-05-26T07:22:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ec085aad2b59916869665f58813daf5d09cbfc9a",
          "body": "Use this link to re-run the recipe: https://app.moderne.io/recipes/org.openrewrite.recipes.rewrite.OpenRewriteRecipeBestPractices?organizationId=QUxML01vZGVybmUvTW9kZXJuZSArIE9wZW5SZXdyaXRl\n\nCo-authored-by: Moderne <team@moderne.io>",
          "is_bot": false,
          "headline": "OpenRewrite recipe best practices",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-05-21T08:01:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "32c775280d6b8d7c8cfc27c8f79889596c2e0201",
          "body": null,
          "is_bot": false,
          "headline": "Handle Kotlin sources in `MockitoWhenOnStaticToMockStatic` (#1003)",
          "author_name": "Merlin Bögershausen",
          "author_login": "MBoegers",
          "committed_at": "2026-05-20T17:43:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6e33f5b9b51515babef19390975a9db136fa7aa3",
          "body": "* Add JUnit 6.1 migration recipes\n\n- Migrate `org.junit.jupiter.engine.Constants` to `org.junit.jupiter.api.Constants`\n- Rename `Executions.started()` to `finished()` for `EngineTestKit`\n- New `MigrateJUnitPioneerToJupiter` recipe for `@DefaultLocale`, `@DefaultTimeZone`,\n  and the system property a\n[…]\n JUnit 6.1 recipes\n\n* Use Lombok getters and simplify ListUtils check in RemoveJreOther\n\n* Remove redundant null/size guard in RemoveJreOther\n\n* Remove redundant reference check in stripOtherFromArray",
          "is_bot": false,
          "headline": "Add JUnit 6.1 migration recipes (#1002)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-05-20T15:32:09Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "da4dd542e87ed2cdfa1080132bae723ef4d33c1f",
          "body": "…ion (#1000)\n\nWhen the delta argument was a non-floating-point literal (e.g. `0`),\n`assertEquals(7f, getHeight(), 0)` was converted to\n`assertThat(getHeight()).as(0).isEqualTo(7f)` because the recipe checked\nthe argument's expression type instead of the resolved method's parameter\ntype. The compiler\n[…]\nrgument is a delta.\n\nNow inspects the resolved parameter type, and inserts an explicit cast on\nthe `within(...)` argument when the literal would otherwise resolve to a\nmismatched `Offset<T>` overload.",
          "is_bot": false,
          "headline": "Fix `assertEquals` delta misinterpreted as message in AssertJ convers…",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-05-18T16:52:10Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0798dafa4c65aef71ecf5c204999db2a750dc1d7",
          "body": "…ourceFile\" (#1001)\n\n* Fix `EnclosedToNested` failing with `Expected to find enclosing JavaSourceFile`\n\n`RemoveAnnotationVisitor` was invoked via `visitNonNull(cd, ctx)` with no\nparent cursor, so its visit walks up an isolated cursor chain that never\nreaches the enclosing `JavaSourceFile`. Pass `get\n[…]\nn the generated\n`tearDownStaticMocks()` and the next method, matching the spacing already\npresent after `setUpStaticMocks()`. Update the expected output so the\ntest reflects the consistent formatting.",
          "is_bot": false,
          "headline": "Fix `EnclosedToNested` failing with \"Expected to find enclosing JavaS…",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-05-18T16:51:57Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6316a74662d7dc424e92573acc3f771270b1c1cd",
          "body": "…ValueSource` (#998)\n\n* Preserve newlines when converting `@CsvSource(textBlock = ...)` to `@ValueSource`\n\nWhen a `@CsvSource(textBlock = ...)` is replaced by `@ValueSource`, each value is now placed on its own indented line instead of being collapsed onto a single line.\n\n* Use `autoFormat` instead of manual padding manipulation",
          "is_bot": false,
          "headline": "Preserve newlines when converting `@CsvSource(textBlock = ...)` to `@…",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-05-16T11:15:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "28b439c284e35163530ea0fd4a5f447b2c9df6a9",
          "body": "…#996)\n\n* Add test demonstrating broken `extends Assert` migration.\n\n* Remove `extends Assert` during JUnit 4 to 5 migration\n\nWhen a class extends `org.junit.Assert`, unqualified inherited\nassertion calls otherwise shadow the Jupiter static imports and\nkeep resolving to the JUnit 4 overloads, producing code that fails\nto compile.\n\n---------\n\nCo-authored-by: Tim te Beek <tim@moderne.io>",
          "is_bot": false,
          "headline": "Fix `JUnit4to5Migration` for classes that extend `org.junit.Assert` (…",
          "author_name": "Craig P. Motlin",
          "author_login": "motlin",
          "committed_at": "2026-05-15T17:09:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9f8b6e7e985244211dbe568e1e7adada55f98f3c",
          "body": "* OpenRewrite recipe best practices\n\nUse this link to re-run the recipe: https://app.moderne.io/recipes/org.openrewrite.recipes.rewrite.OpenRewriteRecipeBestPractices?organizationId=QUxML01vZGVybmUvTW9kZXJuZSArIE9wZW5SZXdyaXRl\n\nCo-authored-by: Moderne <team@moderne.io>\n\n* Update JUnit6BestPracticesTest.java\n\n---------\n\nCo-authored-by: Moderne <team@moderne.io>\nCo-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>",
          "is_bot": false,
          "headline": "OpenRewrite recipe best practices (#997)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-05-15T11:12:54Z",
          "body_truncated": false,
          "is_coding_agent": true
        },
        {
          "oid": "10384e5055c45ccfcebfe6a30f0e602e93fe2870",
          "body": "Use this link to re-run the recipe: https://app.moderne.io/recipes/org.openrewrite.recipes.rewrite.OpenRewriteRecipeBestPractices?organizationId=QUxML01vZGVybmUvTW9kZXJuZSArIE9wZW5SZXdyaXRl\n\nCo-authored-by: Moderne <team@moderne.io>",
          "is_bot": false,
          "headline": "OpenRewrite recipe best practices",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-05-15T10:53:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ddd9959fb52ec6c90eedbfe6ef9a1349fc72ab39",
          "body": null,
          "is_bot": false,
          "headline": "Cleanup junit vintage engine (#993)",
          "author_name": "sullis",
          "author_login": "sullis",
          "committed_at": "2026-05-08T12:45:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "97d3a00b406f21a67bb8cbc3e8676120774ca1c3",
          "body": null,
          "is_bot": false,
          "headline": "Add unit test for JUnit6BestPractices (#994)",
          "author_name": "sullis",
          "author_login": "sullis",
          "committed_at": "2026-05-08T06:38:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "94343228a8189e274aefc975c2791a100049a6cd",
          "body": "…parisonToAssertEquals` (#995)\n\n`UseAssertSame` was rewriting `assertTrue(wrapper == primitive)` to\n`assertSame(wrapper, primitive)`, which fails: Java unboxes for `==`,\nbut `assertSame` autoboxes the primitive into a new wrapper and\ncompares by reference. Closes the gap left by #992 (primitive-primitive\nonly) by also handling the mixed wrapper-primitive form, with\n`AssertTrueComparisonToAssertEquals` extended to accept it.",
          "is_bot": false,
          "headline": "Skip wrapper-primitive in `UseAssertSame`; rewrite via `AssertTrueCom…",
          "author_name": "Craig P. Motlin",
          "author_login": "motlin",
          "committed_at": "2026-05-08T06:34:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "22b9122976eff23c533fada6bdf834cb68092991",
          "body": "Converting `assertTrue(a == b)` to `assertSame(a, b)` changes value\nequality into reference equality on the boxed types, which fails for\nmixed primitive types like `123L == 123`.",
          "is_bot": false,
          "headline": "Skip primitive comparisons in `UseAssertSame` (#992)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-05-05T22:35:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9104c055bd48e2e158533b35392bf85acabb9aa6",
          "body": "* Support `textBlock` attribute in `CsvSourceToValueSource`\n\nResolves #985\n\n* Skip textBlock conversion when values contain single quotes\n\nSingle quote is CsvSource's default quote character, so converting\n'apple' to a ValueSource string literal would change the parsed value.\n\n* Use `StringUtils.con\n[…]\nnsWhitespace` and inline trivial checks\n\nReplaces three local helpers with `StringUtils.containsWhitespace` for\nthe whitespace check and inline `String#indexOf` calls for the single-\ncharacter checks.",
          "is_bot": false,
          "headline": "Support `textBlock` attribute in `CsvSourceToValueSource` (#989)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-05-05T09:48:09Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b23a699aea34d008c13ca43f50362a652c2b12c6",
          "body": "…` (#990)\n\nRemoving an explicit `openMocks(this)` call shifts `@Mock` fields onto\nthe extension/runner's strict mocking session, which may surface\n`UnnecessaryStubbingException` for tests that previously benefited from\nthe lenient mocks created by `openMocks`. Mention the opt-out via\n`@MockitoSettings(strictness = Strictness.LENIENT)`.\n\nRefs #987",
          "is_bot": false,
          "headline": "Document strictness implication of `RemoveInitMocksIfRunnersSpecified…",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-05-04T21:08:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b06f6a4d6aa4a362a30b58784b79c797f8e3cf4d",
          "body": "The captor registers a matcher used to capture values during later\nreal invocations; removing the stubbing breaks the capture.",
          "is_bot": false,
          "headline": "Preserve `doNothing()` stubbings using `ArgumentCaptor.capture()` (#988)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-05-04T18:51:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "41ace45e65e1766cd71de8f81b9afb8b186b356e",
          "body": "…...\")` (#983)\n\n* Guard PrepareForTest fullyQualifiedNames cast against ClassCastException\n\nAdd an `instanceof J.NewArray` check before casting the assignment value\nin `extractPrepareForTestClasses`, so `@PrepareForTest(fullyQualifiedNames = \"...\")`\nwith a string literal no longer crashes the recipe\n[…]\nsages such as\n`@PrepareForTest(fullyQualifiedNames = \"...\")` or\n`@PrepareForTest(fullyQualifiedNames = {\"a\",\"b\"})` leave the source intact\ninstead of stripping an annotation the recipe cannot migrate.",
          "is_bot": false,
          "headline": "Fix `ClassCastException` for `@PrepareForTest(fullyQualifiedNames = \"…",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-05-01T16:33:49Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "67482655a174b463becab942387ddfadeca8cb8d",
          "body": "Switch the JavaTemplate to take `Class<?>` directly and construct a\nproper class literal so the resulting `assertInstanceOf` invocation\ncarries type info, allowing `maybeAddImport` to add the missing static\nimport.",
          "is_bot": false,
          "headline": "Fix AssertTrueInstanceofToAssertInstanceOf static import (#984)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-05-01T11:36:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f3a0fb90305c123e0a1bf4747b459c64ea6207a8",
          "body": "Restrict to files that actually import PowerMockito, so plain\nMockito-only tests no longer run through PowerMockito conversion logic.\n\nFixes #980",
          "is_bot": false,
          "headline": "Tighten PowerMockitoMockStaticToMockito precondition (#981)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-04-29T22:18:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a298e6b4233e625a341a603796c6af8a1aed9b1b",
          "body": "* Upgrade junit-bom to 6.x in JUnit 5 to 6 migration\n\nThe JUnit5to6Migration recipe upgraded individual junit-jupiter\nartifacts but left the org.junit:junit-bom import managed in\ndependencyManagement on 5.x, including when its version was\nreferenced through a property.\n\n* Use recipeFromResources in JUnit5to6MigrationTest\n\n* Return assertion actual() instead of explicit return",
          "is_bot": false,
          "headline": "Upgrade junit-bom to 6.x in JUnit 5 to 6 migration (#978)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-04-29T21:47:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c1bf1c1b5a3f08478325a6f38fc40a4390c04529",
          "body": "The \"remove bare mockStatic\" guard didn't recognize J.Return as a valid\nancestor, so mockStatic(X.class) returned from a helper was nullified —\ncollapsing the return statement to `return;` and breaking compilation\nagainst the helper's MockedStatic<X> return type.",
          "is_bot": false,
          "headline": "Preserve mockStatic when returned from helper methods (#979)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-04-29T21:45:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9bd6b9f7aa615f8c4dbd1712ecfae18ac48e73fc",
          "body": "Use this link to re-run the recipe: https://app.moderne.io/recipes/org.openrewrite.recipes.rewrite.OpenRewriteRecipeBestPractices?organizationId=QUxML01vZGVybmUvTW9kZXJuZSArIE9wZW5SZXdyaXRl\n\nCo-authored-by: Moderne <team@moderne.io>",
          "is_bot": false,
          "headline": "OpenRewrite recipe best practices",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-04-29T09:59:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "56f133a6de462b1222ac3acc1f4e8339e32f3137",
          "body": null,
          "is_bot": false,
          "headline": "Cleanup Mockito AutoCloseable fields (#977)",
          "author_name": "sullis",
          "author_login": "sullis",
          "committed_at": "2026-04-28T21:10:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "de80c8f5a402b909bdce4f49f1fbaa38c7943179",
          "body": "Use this link to re-run the recipe: https://app.moderne.io/recipes/org.openrewrite.recipes.rewrite.OpenRewriteRecipeBestPractices?organizationId=QUxML01vZGVybmUvTW9kZXJuZSArIE9wZW5SZXdyaXRl\n\nCo-authored-by: Moderne <team@moderne.io>",
          "is_bot": false,
          "headline": "OpenRewrite recipe best practices",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-04-28T10:20:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "130258985b4dba189cdf403961d4a72404965a3f",
          "body": "Use this link to re-run the recipe: https://dev.moderne.io/recipes/org.openrewrite.java.recipes.DeclarativeSingleton?organizationId=QUxML01vZGVybmUvTW9kZXJuZSArIE9wZW5SZXdyaXRl#defaults=W3sidmFsdWUiOltdLCJuYW1lIjoiZXhjbHVzaW9ucyJ9XQ==\n\nCo-authored-by: Moderne <team@moderne.io>",
          "is_bot": false,
          "headline": "Make declarative recipes singletons",
          "author_name": "Sam Snyder",
          "author_login": "sambsnyd",
          "committed_at": "2026-04-24T20:37:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "92de89a921d1db7934afad066065ce6083ea6176",
          "body": "The recipe asked for `okhttp-4.10` via `classpathFromResources`, but\nthat artifact is only bundled in the test type table — production runs\nof the recipe (e.g. via the Moderne CLI) fail with\n`IllegalArgumentException: Unable to find classpath resource\ndependencies beginning with: 'okhttp-4.10'` when\n[…]\nalready lenient about\nunresolved members), so dropping the unused `okhttp-4.10` request is\nsufficient and matches the sister `UpdateMockWebServerMockResponse`\nrecipe, which uses just `mockwebserver3`.",
          "is_bot": false,
          "headline": "Fix UpdateMockWebServerDispatcher classpath lookup (#975)",
          "author_name": "Knut Wannheden",
          "author_login": "knutwannheden",
          "committed_at": "2026-04-23T06:18:45Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "64260b8db6a8169dd3c655c523fb40ff538ce3e4",
          "body": "Use this link to re-run the recipe: https://app.moderne.io/recipes/org.openrewrite.java.recipes.ExamplesExtractor?organizationId=QUxML09wZW4gU291cmNlL09wZW5SZXdyaXRl\n\nCo-authored-by: Moderne <team@moderne.io>",
          "is_bot": false,
          "headline": "Extract documentation examples from tests",
          "author_name": "Greg Oledzki",
          "author_login": "greg-at-moderne",
          "committed_at": "2026-04-21T07:05:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e09430b9f7f8146ae5917a97135b70359982972e",
          "body": "…ion (#966)\n\n* Add @MockitoSettings(strictness = Strictness.WARN) support for Mockito migration\n\nAddresses the UnnecessaryStubbingException issue that occurs after migrating\nfrom Mockito 1.x, where unused stubbings were silently ignored but now fail\nunder MockitoExtension's default STRICT_STUBS stri\n[…]\nindAnnotations check, move maybeAddImport calls next to their\ntemplates, and use a static import for Comparator.comparing.\n\n* Use direct return\n\n---------\n\nCo-authored-by: Tim te Beek <tim@moderne.io>",
          "is_bot": false,
          "headline": "Add @MockitoSettings(strictness = Strictness.WARN) for Mockito migrat…",
          "author_name": "Benjamin Muschko",
          "author_login": "bmuschko",
          "committed_at": "2026-04-18T10:32:32Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f041383697177b175a94e1fcf51e25c425253414",
          "body": "…(#972)\n\n* Fix MockWebServer Dispatcher return type and RecordedRequest renames\n\nRestore the `MockResponse` return type on `Dispatcher.dispatch()`\noverrides after the blanket `MockResponse` → `MockResponse.Builder`\nrename, wrapping return expressions with `.build()`. Also rename\n`RecordedRequest.get\n[…]\nch delegates type attribution to the parser and removes the\nTree/Collections imports.\n\n* Regenerate recipes.csv for UpdateMockWebServerDispatcher\n\n* Use MethodMatcher for dispatch() override detection",
          "is_bot": false,
          "headline": "Fix MockWebServer Dispatcher return type and RecordedRequest renames …",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-04-17T16:40:30Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "13f0a17295a7c3d8921eafa766534738b5f2f2e5",
          "body": "Use this link to re-run the recipe: https://app.moderne.io/recipes/org.openrewrite.recipes.rewrite.OpenRewriteRecipeBestPractices?organizationId=QUxML01vZGVybmUvTW9kZXJuZSArIE9wZW5SZXdyaXRl\n\nCo-authored-by: Moderne <team@moderne.io>",
          "is_bot": false,
          "headline": "OpenRewrite recipe best practices",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-04-17T11:01:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "83d1f44e611143ee6d1b9bec6aa7a33820ea04bd",
          "body": "…971)\n\nFollow-up to #970, which disabled `doNotChangeAlreadyUnitTestMethods` with\ncomment \"flaky on CI but I don't know why\".\n\nRoot cause: as of rewrite 8.79.4 (openrewrite/rewrite#7364), the Kotlin\nparser maps non-nullable `kotlin.Unit` to JVM `JavaType.Primitive.Void`.\n`TypeUtils.isOfClassType(typ\n[…]\ne was CI-only.\n\nUse `KotlinTypeUtils.isKotlinUnit` (introduced in the same PR #7364)\nwhich accepts either `JavaType.Primitive.Void` or a `kotlin.Unit` class\nreference, and re-enable the disabled test.",
          "is_bot": false,
          "headline": "Use KotlinTypeUtils.isKotlinUnit to match Kotlin void return types (#…",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-04-16T21:59:14Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "675b57d5da25e6a02ab84231be124c02a6c8888c",
          "body": "…da expressions (#970)\n\n* Fix RemoveTryCatchFailBlocks failing when removing blocks within lambda expressions\n\n* Maybe this will fix test failure seen on CI\n\n* Disable the test because I don't care enough to investigate why it's failing on CI but not locally",
          "is_bot": false,
          "headline": "Fix RemoveTryCatchFailBlocks failing when removing blocks within lamb…",
          "author_name": "Sam Snyder",
          "author_login": "sambsnyd",
          "committed_at": "2026-04-15T22:15:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ea724781c80db6ee42eab3443689f1c8e154d893",
          "body": "* Fix ClassCastException in RemoveTimesZeroAndOne when verify arg is not a method invocation (#968)\n\n* Add @Issue annotation to retainVerificationModeIdentifier test",
          "is_bot": false,
          "headline": "Fix ClassCastException in RemoveTimesZeroAndOne (#969)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-04-13T10:52:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "58bcc123e91b2aaef3d5f36a0ba728f8e6586f1c",
          "body": "* Add MigrateToKafkaNative recipe for Testcontainers (#568)\n\n* Address review feedback on ReplaceContainerImageName\n\n- Use @RequiredArgsConstructor with @Getter final fields for displayName/description\n- Make MethodMatcher a static field\n- Use UsesMethod precondition instead of UsesType\n- Also handl\n[…]\nalents:\n- yandex/clickhouse-server -> clickhouse/clickhouse-server\n- shopify/toxiproxy -> ghcr.io/shopify/toxiproxy\n- vault -> hashicorp/vault\n\nWhen newImage has no tag, the original tag is preserved.",
          "is_bot": false,
          "headline": "Add MigrateToKafkaNative recipe for Testcontainers (#568) (#967)",
          "author_name": "Tim te Beek",
          "author_login": "timtebeek",
          "committed_at": "2026-04-11T21:32:29Z",
          "body_truncated": true,
          "is_coding_agent": false
        }
      ],
      "releases_count": 100,
      "commits_last_year": 314,
      "latest_release_at": "2026-07-20T14:04:34Z",
      "latest_release_tag": "v3.42.1",
      "releases_from_tags": false,
      "days_since_last_push": 0,
      "active_weeks_last_year": 52,
      "days_since_latest_release": 5,
      "mean_days_between_releases": 9.4
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": true,
      "health_percentage": 62,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": true
    },
    "ecosystem": {
      "packages": []
    },
    "popularity": {
      "forks": 104,
      "stars": 99,
      "watchers": 7,
      "fork_history": {
        "days": [
          {
            "date": "2020-12-02",
            "count": 1
          },
          {
            "date": "2021-05-19",
            "count": 1
          },
          {
            "date": "2021-06-15",
            "count": 1
          },
          {
            "date": "2021-07-28",
            "count": 1
          },
          {
            "date": "2021-08-08",
            "count": 1
          },
          {
            "date": "2021-08-20",
            "count": 1
          },
          {
            "date": "2022-02-10",
            "count": 1
          },
          {
            "date": "2022-02-19",
            "count": 1
          },
          {
            "date": "2022-05-30",
            "count": 1
          },
          {
            "date": "2022-06-06",
            "count": 1
          },
          {
            "date": "2022-11-22",
            "count": 1
          },
          {
            "date": "2022-11-27",
            "count": 1
          },
          {
            "date": "2023-01-18",
            "count": 1
          },
          {
            "date": "2023-01-26",
            "count": 1
          },
          {
            "date": "2023-01-31",
            "count": 1
          },
          {
            "date": "2023-03-22",
            "count": 1
          },
          {
            "date": "2023-04-12",
            "count": 1
          },
          {
            "date": "2023-04-15",
            "count": 1
          },
          {
            "date": "2023-04-28",
            "count": 1
          },
          {
            "date": "2023-05-05",
            "count": 1
          },
          {
            "date": "2023-05-13",
            "count": 1
          },
          {
            "date": "2023-05-16",
            "count": 1
          },
          {
            "date": "2023-05-17",
            "count": 1
          },
          {
            "date": "2023-05-18",
            "count": 1
          },
          {
            "date": "2023-05-23",
            "count": 1
          },
          {
            "date": "2023-07-05",
            "count": 1
          },
          {
            "date": "2023-07-19",
            "count": 1
          },
          {
            "date": "2023-07-29",
            "count": 1
          },
          {
            "date": "2023-08-01",
            "count": 1
          },
          {
            "date": "2023-08-02",
            "count": 1
          },
          {
            "date": "2023-09-08",
            "count": 1
          },
          {
            "date": "2023-10-01",
            "count": 1
          },
          {
            "date": "2023-10-13",
            "count": 1
          },
          {
            "date": "2023-10-18",
            "count": 1
          },
          {
            "date": "2023-11-09",
            "count": 1
          },
          {
            "date": "2023-11-22",
            "count": 1
          },
          {
            "date": "2023-12-18",
            "count": 1
          },
          {
            "date": "2024-01-08",
            "count": 1
          },
          {
            "date": "2024-01-25",
            "count": 1
          },
          {
            "date": "2024-01-31",
            "count": 1
          },
          {
            "date": "2024-02-18",
            "count": 1
          },
          {
            "date": "2024-04-12",
            "count": 1
          },
          {
            "date": "2024-05-16",
            "count": 1
          },
          {
            "date": "2024-05-20",
            "count": 1
          },
          {
            "date": "2024-06-04",
            "count": 1
          },
          {
            "date": "2024-06-07",
            "count": 1
          },
          {
            "date": "2024-06-15",
            "count": 1
          },
          {
            "date": "2024-06-19",
            "count": 1
          },
          {
            "date": "2024-06-25",
            "count": 1
          },
          {
            "date": "2024-07-03",
            "count": 1
          },
          {
            "date": "2024-07-08",
            "count": 1
          },
          {
            "date": "2024-07-23",
            "count": 1
          },
          {
            "date": "2024-08-13",
            "count": 1
          },
          {
            "date": "2024-08-14",
            "count": 1
          },
          {
            "date": "2024-09-06",
            "count": 1
          },
          {
            "date": "2024-09-07",
            "count": 1
          },
          {
            "date": "2024-09-09",
            "count": 1
          },
          {
            "date": "2024-09-11",
            "count": 1
          },
          {
            "date": "2024-09-16",
            "count": 1
          },
          {
            "date": "2024-10-10",
            "count": 1
          },
          {
            "date": "2024-10-15",
            "count": 1
          },
          {
            "date": "2024-10-29",
            "count": 1
          },
          {
            "date": "2024-10-31",
            "count": 1
          },
          {
            "date": "2024-11-05",
            "count": 1
          },
          {
            "date": "2024-11-17",
            "count": 1
          },
          {
            "date": "2024-12-04",
            "count": 1
          },
          {
            "date": "2024-12-06",
            "count": 1
          },
          {
            "date": "2024-12-20",
            "count": 2
          },
          {
            "date": "2024-12-27",
            "count": 1
          },
          {
            "date": "2025-01-13",
            "count": 1
          },
          {
            "date": "2025-01-26",
            "count": 1
          },
          {
            "date": "2025-02-11",
            "count": 1
          },
          {
            "date": "2025-04-10",
            "count": 1
          },
          {
            "date": "2025-04-18",
            "count": 1
          },
          {
            "date": "2025-04-19",
            "count": 1
          },
          {
            "date": "2025-06-06",
            "count": 1
          },
          {
            "date": "2025-06-10",
            "count": 1
          },
          {
            "date": "2025-07-13",
            "count": 1
          },
          {
            "date": "2025-08-13",
            "count": 1
          },
          {
            "date": "2025-08-20",
            "count": 1
          },
          {
            "date": "2025-09-09",
            "count": 1
          },
          {
            "date": "2025-09-24",
            "count": 1
          },
          {
            "date": "2025-10-16",
            "count": 1
          },
          {
            "date": "2025-10-26",
            "count": 1
          },
          {
            "date": "2025-10-27",
            "count": 1
          },
          {
            "date": "2025-11-06",
            "count": 1
          },
          {
            "date": "2025-11-18",
            "count": 1
          },
          {
            "date": "2025-11-24",
            "count": 1
          },
          {
            "date": "2025-12-07",
            "count": 1
          },
          {
            "date": "2026-01-04",
            "count": 1
          },
          {
            "date": "2026-01-07",
            "count": 1
          },
          {
            "date": "2026-01-18",
            "count": 1
          },
          {
            "date": "2026-01-27",
            "count": 1
          },
          {
            "date": "2026-02-11",
            "count": 1
          },
          {
            "date": "2026-03-23",
            "count": 1
          },
          {
            "date": "2026-05-28",
            "count": 1
          },
          {
            "date": "2026-06-19",
            "count": 1
          },
          {
            "date": "2026-07-10",
            "count": 1
          },
          {
            "date": "2026-07-11",
            "count": 1
          },
          {
            "date": "2026-07-14",
            "count": 1
          },
          {
            "date": "2026-07-25",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 102,
        "total_forks": 104
      },
      "star_history": null,
      "open_issues_and_prs": 23
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [
        "build.gradle.kts"
      ],
      "largest_source_bytes": 73880,
      "source_files_sampled": 402,
      "oversized_source_files": 3,
      "agent_instruction_files": [],
      "agent_instruction_max_bytes": null
    },
    "dependencies": {
      "manifests": [
        "build.gradle.kts"
      ],
      "advisories": {
        "error": null,
        "scope": null,
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "maven"
      ],
      "dependencies": [],
      "all_dependencies": {
        "error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
        "source": null,
        "packages": [],
        "collected": false,
        "truncated": false,
        "total_count": null,
        "direct_count": null,
        "indirect_count": null
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 603,
        "open_issues": 23,
        "closed_ratio": 0.94,
        "closed_issues": 361,
        "closed_unmerged_prs": 68
      },
      "bus_factor": 3,
      "bot_contributors": 2,
      "top_contributors": [
        {
          "type": "User",
          "login": "timtebeek",
          "commits": 431,
          "avatar_url": "https://avatars.githubusercontent.com/u/1027334?v=4"
        },
        {
          "type": "User",
          "login": "pway99",
          "commits": 138,
          "avatar_url": "https://avatars.githubusercontent.com/u/22326988?v=4"
        },
        {
          "type": "User",
          "login": "jkschneider",
          "commits": 125,
          "avatar_url": "https://avatars.githubusercontent.com/u/1697736?v=4"
        },
        {
          "type": "User",
          "login": "sambsnyd",
          "commits": 121,
          "avatar_url": "https://avatars.githubusercontent.com/u/8549033?v=4"
        },
        {
          "type": "User",
          "login": "aegershman",
          "commits": 83,
          "avatar_url": "https://avatars.githubusercontent.com/u/5619476?v=4"
        },
        {
          "type": "User",
          "login": "knutwannheden",
          "commits": 61,
          "avatar_url": "https://avatars.githubusercontent.com/u/408765?v=4"
        },
        {
          "type": "User",
          "login": "tkvangorder",
          "commits": 32,
          "avatar_url": "https://avatars.githubusercontent.com/u/1878529?v=4"
        },
        {
          "type": "User",
          "login": "amishra-u",
          "commits": 20,
          "avatar_url": "https://avatars.githubusercontent.com/u/119983081?v=4"
        },
        {
          "type": "User",
          "login": "steve-aom-elliott",
          "commits": 20,
          "avatar_url": "https://avatars.githubusercontent.com/u/7945003?v=4"
        },
        {
          "type": "User",
          "login": "MBoegers",
          "commits": 17,
          "avatar_url": "https://avatars.githubusercontent.com/u/7557397?v=4"
        }
      ],
      "contributors_sampled": 98,
      "top_contributor_share": 0.318
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "ci.yml",
        "publish.yml",
        "repository-backup.yml",
        "stale.yml"
      ],
      "has_docs_dir": false,
      "linter_configs": [],
      "has_editorconfig": true,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 9,
            "reason": "binaries present in source code",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 0,
            "reason": "branch protection not enabled on development/release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 9,
            "reason": "22 out of 23 merged PRs checked by a CI test -- score normalized to 9",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 2,
            "reason": "Found 8/30 approved changesets -- score normalized to 2",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 10,
            "reason": "project has 16 contributing companies or organizations",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 10,
            "reason": "update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 9,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 10,
            "reason": "30 commit(s) and 12 issue activity found in the last 90 days -- score normalized to 10",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": null,
            "reason": "packaging workflow not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 0,
            "reason": "dependency not pinned by hash detected -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "SAST tool is not run on all commits -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": null,
            "reason": "no releases found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": 0,
            "reason": "detected GitHub workflow tokens with excessive permissions",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 10,
            "reason": "0 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "c9ebc4f47b33d470bd739fa9930fd391df565112",
        "ran_at": "2026-07-25T17:21:02Z",
        "aggregate_score": 5.2,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": true
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-25T07:28:02Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": "2026-07-25T07:19:00Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": [
        {
          "number": 91,
          "created_at": "2021-03-24T19:08:03Z",
          "last_comment_at": "2024-06-22T13:47:54Z",
          "last_comment_author": "MBoegers"
        },
        {
          "number": 195,
          "created_at": "2022-03-28T18:40:55Z",
          "last_comment_at": "2022-04-15T21:14:45Z",
          "last_comment_author": "pway99"
        },
        {
          "number": 196,
          "created_at": "2022-03-28T18:47:53Z",
          "last_comment_at": "2022-03-28T21:36:03Z",
          "last_comment_author": "pway99"
        },
        {
          "number": 197,
          "created_at": "2022-03-28T19:59:17Z",
          "last_comment_at": "2022-03-28T21:48:00Z",
          "last_comment_author": "pway99"
        },
        {
          "number": 203,
          "created_at": "2022-03-30T15:44:34Z",
          "last_comment_at": "2022-03-30T20:04:42Z",
          "last_comment_author": "tkvangorder"
        },
        {
          "number": 221,
          "created_at": "2022-04-18T14:42:36Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 224,
          "created_at": "2022-04-27T16:15:19Z",
          "last_comment_at": "2025-09-02T13:54:46Z",
          "last_comment_author": "timtebeek"
        },
        {
          "number": 225,
          "created_at": "2022-04-27T16:16:46Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 231,
          "created_at": "2022-06-06T18:22:00Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 278,
          "created_at": "2022-10-27T20:51:53Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 318,
          "created_at": "2023-02-23T03:13:25Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 438,
          "created_at": "2023-12-05T11:52:15Z",
          "last_comment_at": "2023-12-05T11:53:38Z",
          "last_comment_author": "timtebeek"
        },
        {
          "number": 453,
          "created_at": "2024-01-04T15:50:35Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 458,
          "created_at": "2024-01-15T20:01:01Z",
          "last_comment_at": "2024-08-20T09:01:16Z",
          "last_comment_author": "timtebeek"
        },
        {
          "number": 508,
          "created_at": "2024-04-17T11:10:59Z",
          "last_comment_at": "2024-04-30T22:34:23Z",
          "last_comment_author": "kernanj"
        },
        {
          "number": 522,
          "created_at": "2024-06-13T10:49:53Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 529,
          "created_at": "2024-06-17T13:20:51Z",
          "last_comment_at": "2024-06-26T09:27:58Z",
          "last_comment_author": "timtebeek"
        },
        {
          "number": 697,
          "created_at": "2025-04-09T16:43:07Z",
          "last_comment_at": "2025-05-04T11:23:27Z",
          "last_comment_author": "timtebeek"
        },
        {
          "number": 723,
          "created_at": "2025-05-07T09:24:06Z",
          "last_comment_at": "2025-05-09T06:25:57Z",
          "last_comment_author": "stefan-schilling"
        },
        {
          "number": 738,
          "created_at": "2025-05-24T19:55:24Z",
          "last_comment_at": "2025-05-28T22:38:21Z",
          "last_comment_author": "timtebeek"
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/openrewrite/rewrite-testing-frameworks",
    "host": "github.com",
    "name": "rewrite-testing-frameworks",
    "owner": "openrewrite"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "good",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 72,
      "inputs": {
        "security": 52,
        "vitality": 100,
        "community": 61,
        "governance": 77,
        "engineering": 63
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "excellent",
        "name": "Vitality",
        "value": 100,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "excellent",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "commits_last_year": 314,
              "human_commit_share": 1,
              "days_since_last_push": 0,
              "active_weeks_last_year": 52
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 0 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "52/52 weeks with commits",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 52
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "314 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 314
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 12 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "releases_count": 100,
              "latest_release_tag": "v3.42.1",
              "releases_from_tags": false,
              "days_since_latest_release": 5,
              "mean_days_between_releases": 9.4
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "100 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 100
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 5 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 5
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~9.4 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 9.4
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "maintained",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": null,
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": 0,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "last human commit 0 days ago",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_maintained",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "moderate",
        "name": "Community & Adoption",
        "value": 61,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "moderate",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 53,
            "inputs": {
              "forks": 104,
              "stars": 99,
              "watchers": 7,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "99 stars",
                "points": 32.3,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 99
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "104 forks",
                "points": 16.8,
                "status": "partial",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 104
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "7 watchers",
                "points": 4.3,
                "status": "partial",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 7
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "good",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 71,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": true,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "has_pull_request_template": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file present, not a recognized license",
                "points": 16.9,
                "status": "partial",
                "details": [
                  {
                    "code": "license_custom",
                    "params": {}
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 18,
                "status": "met",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 6.3,
                "status": "met",
                "details": [],
                "max_points": 6.3
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "good",
        "name": "Sustainability & Governance",
        "value": 77,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "good",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 75,
            "inputs": {
              "bus_factor": 3,
              "contributors_sampled": 98,
              "top_contributor_share": 0.318
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "3 contributor(s) cover half of all commits",
                "points": 36,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 3
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 32% of commits",
                "points": 15.3,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 32
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "98 contributors",
                "points": 13.5,
                "status": "met",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 98
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 16 contributing companies or organizations",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "good",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 81,
            "inputs": {
              "merged_prs": 603,
              "open_issues": 23,
              "closed_issues": 361,
              "issue_closed_ratio": 0.94,
              "closed_unmerged_prs": 68
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "94% of issues closed",
                "points": 43.9,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 94
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "603/671 decided PRs merged",
                "points": 34.4,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 603,
                      "decided": 671
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 8/30 approved changesets -- score normalized to 2",
                "points": 3,
                "status": "partial",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "good",
            "name": "Ownership & stewardship",
            "note": null,
            "notes": [],
            "value": 76,
            "inputs": {
              "followers": 984,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "openrewrite",
              "public_repos": 75,
              "account_age_days": 2341
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "organization-owned",
                "points": 30,
                "status": "met",
                "details": [
                  {
                    "code": "owner_organization",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "984 followers of openrewrite",
                "points": 21.5,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 984,
                      "login": "openrewrite"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "75 public repos, account ~6 yr old",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 75
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 6
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "moderate",
        "name": "Engineering Quality",
        "value": 63,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "good",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 72,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": true,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "4 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 4
                    }
                  }
                ],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 6.4,
                "status": "met",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "22 out of 23 merged PRs checked by a CI test -- score normalized to 9",
                "points": 18,
                "status": "partial",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "moderate",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "topics": [
                "openrewrite",
                "openrewrite-recipes"
              ],
              "has_wiki": false,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": false,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": "2 topics",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "topics_count",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "moderate",
        "name": "Security",
        "value": 52,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "moderate",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Packaging, Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "packaging",
                    "signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 52,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 16,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 2,
              "scorecard_aggregate": 5.2
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "binaries present in source code",
                "points": 6.8,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection not enabled on development/release branches",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "22 out of 23 merged PRs checked by a CI test -- score normalized to 9",
                "points": 2.2,
                "status": "partial",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 8/30 approved changesets -- score normalized to 2",
                "points": 1.5,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 16 contributing companies or organizations",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "update tool detected",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.2,
                "status": "partial",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "30 commit(s) and 12 issue activity found in the last 90 days -- score normalized to 10",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow not detected",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "SAST tool is not run on all commits -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "detected GitHub workflow tokens with excessive permissions",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "0 existing vulnerabilities detected",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 14
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "moderate",
        "name": "AI Readiness",
        "value": 58,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "at_risk",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 0.9,
              "agent_instruction_files": [],
              "agent_instruction_max_bytes": null
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "no CLAUDE.md / AGENTS.md / editor rules",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_instructions",
                    "params": {}
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "90 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 90,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "moderate",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 55,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [],
              "agent_commit_share": 0.02,
              "toolchain_manifests": [
                "build.gradle.kts"
              ],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "build.gradle.kts (toolchain convention, no task runner)",
                "points": 12.6,
                "status": "partial",
                "details": [
                  {
                    "code": "toolchain_convention",
                    "params": {
                      "files": "build.gradle.kts"
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "Java (statically typed)",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Java"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "2 of the last 100 commits agent-authored or agent-credited",
                "points": 4,
                "status": "partial",
                "details": [
                  {
                    "code": "agent_authored_commits",
                    "params": {
                      "count": 2,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "dependency automation configured, none observed in the sampled commits",
                "points": 5,
                "status": "partial",
                "details": [
                  {
                    "code": "dependency_bot_config_only",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "primary_language": "Java",
              "largest_source_bytes": 73880,
              "source_files_sampled": 402,
              "oversized_source_files": 3
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Java (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Java"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "3/402 source files over 60KB",
                "points": 54.6,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 402,
                      "oversized": 3
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
      }
    ],
    "metrics_version": "1.13.0"
  },
  "warnings": [
    "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-25T17:21:27.863955Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/o/openrewrite/rewrite-testing-frameworks.svg",
  "full_name": "openrewrite/rewrite-testing-frameworks",
  "license_state": "custom",
  "license_spdx": null
}

Bewertungen sind Signale, keine Garantien. Sie spiegeln öffentlich sichtbare Praxis auf GitHub wider — kein Code-Audit und keine Sicherheitsgarantie.

Fehlende Daten werden ausgeschlossen und die Gewichte neu normiert, nie als null bewertet. Die Methodik ist versioniert und offen: Metriken v1.13.0, Schema v0.27.0 — vollständige Methodik · Metriken-Wiki.

Wie ein einzelnes Ergebnis im Gesamtregister steht: aggregierte Statistiken.