---
name: detect-java-version
description: Detect a Maven/Gradle project's real current Java level (by its declared bytecode target, not the build toolchain) and dispatch to the matching one-LTS bump hop (8->11, 11->17, 17->21, 21->25). Use as the entry point: it decides the hop and whether the project should be bumped at all.
---

# Bump a project one Java LTS: two steps: detect, then hop

A project's **build toolchain** (the JDK Gradle/Maven builds *with*) is not its **bytecode target** (the Java
version it *emits*). Many libraries deliberately build with a new JDK but pin old bytecode for consumer reach
(OpenTelemetry instrumentation, Gradle plugins, SDKs). Dispatching on the toolchain mislabels these and tries
an impossible/harmful bump. So always detect the real level first.

## Step 1: detect the real current level + bumpability
`detect_java_version.sh <repo> <sha>` -> JSON. It reads, across all modules, the declared **bytecode target**
(precedence: `options.release` / `<maven.compiler.release>` > `source/targetCompatibility` / `<source>` /
`jvmTarget` > the toolchain `languageVersion`), and reports:
- `detected`, the min bytecode target across modules (the true current Java level).
- `low_target`, true if a bytecode target is pinned below the toolchain, or modules target different levels
  (multi-target), or a `java-gradle-plugin` is applied. These are **deliberate-low-target** projects.
- `bumpable`, true only if a clean single target below the latest LTS and not `low_target`.
- `hop_to`, the next LTS above `detected`.

## Step 2: dispatch
- `bumpable: false` -> **NOT_A_BUMP** (record + stop). Bumping its bytecode would regress its consumers; it
  is not a migration target. Do not score it as a failed bump.
- else -> run the matching per-hop skill for `detected`'s LTS bracket: 8->11, 11->17, 17->21, or 21->25
  (build JDKs are the LTS rungs; a non-LTS detected level brackets down, e.g. 14 -> the 11->17 hop).

The orchestrator `run_repo.sh <repo> <sha> <slug>` does both: detect -> NOT_A_BUMP or dispatch.
