Public record
Software health reportschema 0.27.0 · metrics 1.13.0 · 2026-07-25 17:21 UTC

openrewrite / rewrite-testing-frameworks

OpenRewrite recipes that perform common Java testing migration tasks.

JavaCustom license★ 99 stars⑂ 104 forkssince Sep 2020View on GitHub ↗

openrewrite/rewrite-testing-frameworks holds a health index of 72 out of 100, placing it in the Good band. It scores highest on Vitality (100/100) and lowest on Security (52/100). It was last updated today. 3 contributors account for most of its recent work.

72
overall / 100
Good

Software health index

Metrics are grouped into weighted categories on one standardized 1–100 scale. Overall starts as their weighted mean; when public evidence triggers the High-Risk Jurisdiction Policy, the rating is adjusted and receives an At risk ceiling of 49. AI Readiness sits outside the overall score.

72
Excellent85-100Exemplary; meets essentially all checked criteria
Good70-84Healthy; minor gaps
Moderate50-69Acceptable with notable gaps; review recommended
At risk30-49Significant weaknesses; adoption warrants caution
Critical1-29Severe problems (abandoned, single-maintainer, no hygiene)
VitalityCommunity &AdoptionSustainability &GovernanceEngineeringQualitySecurityAI Readiness

Score profile

Each axis is a category. The shape matters more than the average — a healthy subject fills the whole shape, while a spike-and-crater profile means strength in one dimension is masking risk in another.

Ownership

OpenRewriteOrganization
984 followers75 public repossince Feb 2020

This repository is backed by an organization — shared, accountable stewardship that can outlive any single maintainer.

Metrics by category

Vitality

Is the project alive — is code being written and are releases shipping?

100Excellent · 22% of overall
How it's scored
36/36Push recency — last push 0 days ago
36/36Commit cadence — 52/52 weeks with commits
18/18Commit volume — 314 commits in the last year
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 12 issue activity found in the last 90 days -- score normalized to 10
Inputs used
commits_last_year314
human_commit_share1
days_since_last_push0
active_weeks_last_year52

Release discipline

100Excellent
How it's scored
27/27Ships releases — 100 releases published
36/36Release recency — latest release 5 days ago
27/27Release cadence — a release every ~9.4 days
0/10OpenSSF Scorecard: Signed-Releases — no data
Inputs used
releases_count100
latest_release_tagv3.42.1
releases_from_tagsno
days_since_latest_release5
mean_days_between_releases9.4
Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.

Community & Adoption

Does the project have users, downloads, attention, and a welcoming setup for contributors?

61Moderate · 18% of overall
How it's scored
32.3/60Stars — 99 stars
16.8/25Forks — 104 forks
4.3/15Watchers — 7 watchers
Inputs used
forks104
stars99
watchers7
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
How it's scored
22.5/22.5README
16.9/22.5License — license file present, not a recognized license
18/18CONTRIBUTING guide
0/13.5Code of conduct
0/7.2Issue template
6.3/6.3PR template
Inputs used
has_readmeyes
has_licenseyes
has_contributingyes
has_issue_templateno
has_code_of_conductno
has_pull_request_templateyes

Sustainability & Governance

Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?

77Good · 24% of overall
How it's scored
36/54Bus factor — 3 contributor(s) cover half of all commits
15.3/22.5Commit distribution — top contributor authored 32% of commits
13.5/13.5Contributor breadth — 98 contributors
10/10OpenSSF Scorecard: Contributors — project has 16 contributing companies or organizations
Inputs used
bus_factor3
contributors_sampled98
top_contributor_share0.318
How it's scored
43.9/46.8Issue resolution — 94% of issues closed
34.4/38.3PR acceptance — 603/671 decided PRs merged
3/15OpenSSF Scorecard: Code-Review — Found 8/30 approved changesets -- score normalized to 2
Inputs used
merged_prs603
open_issues23
closed_issues361
issue_closed_ratio0.94
closed_unmerged_prs68
How it's scored
30/30Ownership backing — organization-owned
0/20Verified domain
21.5/25Owner reach — 984 followers of openrewrite
25/25Track record — 75 public repos, account ~6 yr old
Inputs used
followers984
owner_typeOrganization
is_verified
owner_loginopenrewrite
public_repos75
account_age_days2,341

Engineering Quality

Are baseline engineering and documentation practices in place?

63Moderate · 20% of overall
How it's scored
24/24CI workflows — 4 workflow(s)
24/24Tests present
0/16Linter config
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
Inputs used
has_ciyes
has_testsyes
has_editorconfigyes
has_linter_configno
has_precommit_configno

Documentation

50Moderate
How it's scored
30/30README
0/25Documentation directory
0/15Documentation / homepage site
10/10Repository description
10/10Topics — 2 topics
0/10Wiki
Inputs used
topicsopenrewrite, openrewrite-recipes
has_wikino
homepage
has_readmeyes
has_docs_dirno
has_descriptionyes

Security

Are visible security and supply-chain practices strong, without unresolved high-risk jurisdiction exposure?

52Moderate · 16% of overall
How it's scored
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.5License — 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 — no data
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 — no data
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
7.5/7.5Vulnerabilities — 0 existing vulnerabilities detected
Inputs used
sourceopenssf_scorecard
checks_evaluated16
scorecard_versionv5.5.0
checks_inconclusive2
scorecard_aggregate5.2
Excluded from scoring (no data or not applicable): packaging, signed_releases. Remaining weights renormalized.

AI Readiness

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.

58Moderate · 0% of overall
How it's scored
0/45Agent instructions — no CLAUDE.md / AGENTS.md / editor rules
0/15Machine-readable docs (llms.txt)
40/40Legible commit history — 90 of 100 human commits state their intent (structured subject or explanatory body)
Inputs used
has_llms_txtno
legible_history_share0.9
agent_instruction_files
agent_instruction_max_bytes
How it's scored
12.6/18One-command bootstrap — build.gradle.kts (toolchain convention, no task runner)
22/22Automated tests
0/11Lint / format config
11/11Static type checking — Java (statically typed)
0/10Reproducible environment
4/10Demonstrated agent practice — 2 of the last 100 commits agent-authored or agent-credited
5/8Automated maintenance — dependency automation configured, none observed in the sampled commits
0/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
Inputs used
has_nixno
has_testsyes
lockfiles
has_dockerfileno
typed_languageyes
bootstrap_files
has_devcontainerno
has_linter_configno
typecheck_configs
agent_commit_share0.02
toolchain_manifestsbuild.gradle.kts
dependency_bot_commit_share0
How it's scored
45/45Type-checkable code — Java (statically typed)
54.6/55Manageable file sizes — 3/402 source files over 60KB
Inputs used
primary_languageJava
largest_source_bytes73,880
source_files_sampled402
oversized_source_files3

Key facts

99GitHub stars
98contributors
314commits, last 12 months
0days since last push
100releases
3bus factor
23open issues
Mavenpackage ecosystems

Data collection 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

More detail

Star and fork history 0 ★ / 104 ⇿
0Stars
104Forks
100Releases

When each star and fork was added, collected from GitHub and bucketed by day. Cumulative growth sits directly above the daily additions it is made of, so the two read against each other: steady organic accretion looks nothing like an abrupt, short-lived burst. Where that difference is measurable, it is reported as growth authenticity.

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

Each point covers 6 days.

OpenSSF Scorecard 5.2 / 10
5.2aggregate

Independent, tool-agnostic security assessment from the open-source OpenSSF Scorecard. Each check rewards a security practice, not a specific vendor's tool. Checks Scorecard could not determine are marked n/a and excluded from the security score (never counted as zero).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
n/aPackagingpackaging 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
n/aSigned-Releasesno releases found
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
10Vulnerabilities0 existing vulnerabilities detected
All dependencies not collected

The resolved dependency set could not be collected for this report: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Raw JSON report machine-readable
{
  "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
}

Scores are signals, not warranties. They reflect publicly visible practices on GitHub — not a code audit, and not a security guarantee.

Missing data is excluded and weights renormalized, never scored as zero. Methodology is versioned and open: metrics v1.13.0, schema v0.27.0 — full methodology · metrics wiki.

How one result sits in the wider record: aggregate statistics.