How does the Problems Report group entries, and what role does ProblemId (group + id) play in how problems surface to consumers?
answer
- ProblemId = name + display name + group
- ProblemGroup can nest
- report = tree keyed by group → id
- same id aggregated with a count
- stable id = aggregation works
basics
~20 sEach reported problem carries a ProblemId — a stable id plus a ProblemGroup. The report uses that grouping to cluster problems of the same kind under shared headings, so consumers see a tree instead of a flat list.
solid answer
~40 sEvery problem reported through the Problems API is tagged with a **ProblemId**, which combines a stable machine identifier, a human-readable display name, and a **ProblemGroup** that can itself be nested under a parent group. The HTML report and other consumers use this identity to **aggregate and group**: all problems sharing a ProblemId collapse into one entry with a count, and groups form the report's navigation tree. This is why choosing a stable, well-named group hierarchy matters — `ProblemGroup.create("my-plugin", "My Plugin")` with child groups produces clean sections, whereas ad-hoc unique ids per occurrence produce a sprawling, unhelpful report. The same ProblemId is what tooling-API consumers and the configuration cache use to deduplicate and categorize, so the report is just one view over a shared, structured identity rather than free-text strings.
code
kotlin · 11 linesimport org.gradle.api.problems.ProblemGroup
import org.gradle.api.problems.ProblemId
// A stable group + id — reused for EVERY occurrence of this kind of problem
val pluginGroup = ProblemGroup.create("acme-lint", "Acme Lint")
val unusedDepId = ProblemId.create(
"unused-dependency", // stable machine name -> drives grouping/aggregation
"Unused dependency declared", // display name in the HTML report
pluginGroup
)
// Variable detail (which dependency, which file) goes in location/details, NOT the id.go deeper
Know that problems are grouped, not flat, and that grouping comes from an id/group on each problem.
Explain ProblemId = name + display name + ProblemGroup, that groups nest, and that same-id occurrences aggregate with a count.
Discuss id stability as a contract shared by the report and the Tooling API, and how to design a clean group hierarchy.
Set org conventions for ProblemGroup namespacing and id stability so dashboards and CI can track problem frequency across plugins and versions.
## ProblemId: the identity behind every entry When code reports a problem via the Problems API it must supply a **ProblemId**. A ProblemId is built from: - a **name** — a stable, machine-readable string (e.g. `"unused-dependency"`), - a **display name** — the human-readable label shown in the report, - a **ProblemGroup** — a category the id belongs to, which can be nested. You create them roughly like: ```kotlin val group = ProblemGroup.create("my-plugin", "My Plugin") val id = ProblemId.create("unused-dependency", "Unused dependency declared", group) ``` ## How grouping drives the report The HTML report does **not** show problems as a flat chronological log. Instead it builds a **tree keyed by ProblemGroup → ProblemId**: - The top-level nodes are groups (e.g. "Deprecation", "My Plugin"). - Under each group, entries are the distinct ProblemIds. - Multiple occurrences of the *same* ProblemId (e.g. the same deprecation hit in 200 places) are **aggregated** — typically shown once with a count and the list of locations — rather than printed 200 times. This aggregation is the whole point: it turns repetitive noise into a scannable summary. ## Why stability matters Because grouping and deduplication key off the ProblemId, **id stability is a contract**: - If you generate a *new unique id per occurrence* (e.g. embedding a file path in the name), every occurrence becomes its own entry and the report explodes — defeating aggregation. - If you keep ids **stable across builds and versions**, consumers (the report, the Tooling API, CI dashboards) can track a problem over time, filter it, and count its frequency. ## Consumers beyond the HTML The report is one consumer of this identity. The **Tooling API** exposes the same Problem events to IDEs and build tools, and they rely on ProblemId to categorize and route. So designing a clean group hierarchy benefits every consumer at once. ## Practical guidance for plugin authors - Define a small set of stable ProblemGroups for your plugin, nested under a single root group named after the plugin. - Use a fixed id per *kind* of problem; put the variable detail (file, line, value) in the location/details, **not** in the id. - Treat display names as user-facing copy; treat the id as an API you must not casually rename.
- Why is it a mistake to encode the offending file path into the ProblemId name?It makes every occurrence a unique id, so the report can no longer aggregate them — you get hundreds of one-off entries instead of one grouped entry with locations.
- Besides the HTML report, what else consumes ProblemId?The Tooling API surfaces the same Problem events to IDEs and build tools, which use ProblemId to categorize and route diagnostics.
- What goes in the id versus the display name?The id is a stable machine identifier you treat like API; the display name is user-facing copy you can change more freely.
saying these in an interview costs you the question
- Saying the report lists problems in a flat chronological order.
- Putting variable data (paths, values) into the ProblemId name and breaking aggregation.
- Treating ProblemId as a throwaway string rather than a stability contract.