sonar-lessons
Roda a análise do SonarQube do projeto, liga cada grupo de achados à norma ou configuração que o produziu e escreve um arquivo de lições.
sonar-lessons, seção a seção
As seções do próprio SKILL.md da skill, em trechos. Passe o mouse ou clique numa delas para ver quais regras do projeto, templates e arquivos de references/ ela cita. As seções também são chips: clique num para ir até ela.
## Why this is a skill (Form 2) and not an agent
Form 2 because a full verify plus analysis is a side effect the model must not trigger on its own — axis 2 of the design interview: the user types /sonar-lessons, nothing chains it. Publishing the issue was the second such effect until 0103 moved it to /report-issue, the one door from a generated project to the meta-repository. The symptom behind it (axis 1) was the same long prompt pasted into every feature round to produce a Sonar lessons-learned by hand. The closest rejected form was the same skill plus a sonnet collector agent holding the build log and raw JSON; it failed the counter-test of invariant 5, since facets and small pages already keep the extraction short. Record: @.claude/decisions/0100-sonar-lessons-skill.md.
Runs on opus: step 4 — deciding which norm or template owns a finding, and what the fix at the owner is — is the judgment the hand-written lessons-learned needed.
## Procedure
Endpoints, parameters and response fields of every call below: references/sonar-web-api.md. Every curl authenticates with -u "$SONAR_TOKEN:" and never prints the variable.
### 1 · Preconditions — stop on the first that fails
- Root build file:
pom.xml→ maven,build.gradle→ gradle. Neither → stop: nothing to - Scanner declared —
sonar-maven-plugin/org.sonarqubein that file. Absent → stop: sonar.host.urlandsonar.projectKeyread from the build file (sonar.organizationcurl -sS <host>/api/system/statusanswers"status":"UP". Connection refused onSONAR_TOKENset and valid —curl -sS -u "$SONAR_TOKEN:" <host>/api/authentication/validate- Browse permission — one
component_treeread withps=1, the call step 3's duplication
### 2 · Run the analysis
| Tool | Command |
|---|---|
| maven | ./mvnw -B -q verify sonar:sonar |
| gradle | ./gradlew -q build sonar |
-q rather than a redirect to a log file: the output stays short, and a redirect is a write outside this skill's territory. A red build stops here — report the failing module and the first error line; a lessons-learned about an analysis that never ran is fiction.
The analysis is asynchronous. Read ceTaskId from target/sonar/report-task.txt (build/sonar/report-task.txt for gradle) and poll /api/ce/task?id=<ceTaskId> until SUCCESS. Reading measures before that returns the previous analysis, silently. FAILED or CANCELED → stop with the task's errorMessage.
### 3 · Extract
In this order, all read-only:
- Quality gate — status and every condition, with its threshold and actual value.
- Measures — the list in the reference: bugs, vulnerabilities, code smells, hotspots,
- Issues by rule — one call with
ps=1and facets on rules, software qualities, - Rule text —
/api/rules/showfor each rule key: its name and why it matters. - Duplication — files with duplicated blocks, then the blocks of each.
- Coverage — the files with the most uncovered lines.
Large answers are the only real cost of this skill: always request the facet first and page only what step 4 needs.
### 4 · Trace each finding group to its owner
Group by Sonar rule (a duplicated block is its own group). For each group, find the piece of this project's .claude/ that produced it, in this order, and stop at the first hit:
| Origin | How to find it |
|---|---|
| Template copied verbatim | Grep the flagged construct in .claude/skills/*/templates/*.example. A hit means every project gets the issue |
| Norm that allows or requires it | .claude/rules/00-index.md → the norm for that layer; a norm that prescribes the flagged shape, or explicitly permits it |
| Checkstyle / build configuration | config/checkstyle/*.xml and the root build file — a check that is missing, or disabled, where Sonar has the equivalent rule |
| Test template teaches the pattern | Same as the first row, restricted to test-architect and new-feature test templates |
| Code the bootstrap generated | No template in the project — project-bootstrap does not travel. Name it project-bootstrap plus the role of the file (entry point, exception handler, config class) |
| Nothing — the model decided alone | No norm and no template covers the construct. The fix is a norm, or a line in the one that owns that layer |
Then decide the fix at the owner: which file in .claude/, what change, and whether it also needs enforcement (a Checkstyle check, an ArchUnit rule) so the issue cannot come back. Say it concretely — a file path, a line, the shape of the change — never "improve the template".
Check whether an owner file was edited locally since the export: java .claude/hooks/ArchHook.java doctor names the edited .claude/ files. When the file at fault is one of them, the lesson says so: the meta-repository's version may not have the defect.
### 5 · Write `docs/lessons-learned/sonar-NNN.md`
NNN is the highest existing sonar-*.md plus one, 001 when the directory is empty. Fill templates/lessons-learned.md.example: snapshot, issues by origin, one section per group, and the structural lesson — what in .claude/ would have caught the whole class of issue before the analysis did. Complete here: project paths, lines, excerpts all belong in this file.
Progress against the previous run. When sonar-<NNN-1>.md exists, read its snapshot and fill the snapshot's *Previous* and *Δ* columns, and mark each finding group *new*, *recurring* (same rule key in the previous file) or — in a closing list — *gone*. The goal is fewer issues each round; this is the only place that says whether it is happening. A recurring group whose previous file already named the fix at the owner says so: the fix was proposed and has not reached this project (not merged upstream, or not pulled with /arch-adopt).
Report the path and the snapshot line, then go on to step 6.
### 6 · Hand it to `/report-issue` — print the command, invoke nothing
Write not filed yet — /report-issue docs/lessons-learned/sonar-NNN.md in the ## Issue line at the end of sonar-NNN.md, and end the report with that command. /report-issue is manual-only: it picks the sonar-lessons form, strips the project from the body, searches duplicates, asks, and overwrites the ## Issue line with the outcome. The user types it, or the lesson stays local — the line says which, for a later reader and for the next run's step 5.
## Failure modes
No scanner in the build file: `` ❌ pom.xml declares no sonar-maven-plugin. Run /sonarqube-setup, then /sonar-lessons. Nothing written. ``
Server down: `` ❌ http://localhost:9000 refused the connection. Run docker compose up -d sonarqube, wait for /api/system/status to answer UP, re-run. ``
Token missing, invalid, or unable to read: `` ❌ SONAR_TOKEN is not set — export a user token (My Account → Security) and re-run. ❌ <call> answered 403 — SONAR_TOKEN can analyze but not browse this project. A project analysis token cannot read the Web API; use a user token with Browse. ``
Build red: `` ❌ verify failed in <module> — <first error line>. No analysis ran; nothing written. ``
… cortado aqui, o resto está no arquivo
## Report
✅ Sonar lessons — <quality gate status> · <N> issues (<main> main / <test> test) · coverage <x> % · duplication <y> %
Lessons ..... docs/lessons-learned/sonar-NNN.md — <G> groups: <t> template, <r> norm, <c> checkstyle, <b> bootstrap, <m> model alone
Top owners .. <.claude path> (<n> issues) · <.claude path> (<n>) · …
Dashboard ... <host>/dashboard?id=<projectKey>
File it ..... /report-issue docs/lessons-learned/sonar-NNN.mdO que lê, escreve e recusa
O contrato da própria skill, do SKILL.md, no texto original.
Class
report — the territory is skill_classes.report in @.claude/schemas/extensions.json: docs/lessons-learned/**, nothing else. ArchHook.java guard enforces it; target/ and build/, which the analysis writes, are ignored by git and outside what guard sweep sees.
Reads
the root build file, target/sonar/report-task.txt (or build/sonar/), .claude/rules/**, .claude/skills/*/templates/, config/checkstyle/, .claude/.arch-provenance.json (the version line of the file), and the SonarQube Web API.
Writes
docs/lessons-learned/sonar-NNN.md.
Publishes
nothing. The issue is /report-issue's, typed by the user with the path step 6 prints; the body file sonar-NNN.issue.md is written there.
Never writes
the build file, docker-compose.yml, a token, or anything under src/. A finding is fixed at its owner in the meta-repository, or by /new-feature in this project — not by this skill.
Not chained
by any skill. Travels into the generated project (export.skills.include); in the Nerviz repository itself it stops at step 1, which has no build file.
Fonte: SKILL.md § Contract, no nerviz e4cae27.
O que o guard faz com ela
report é a classe da skill, e a lista à esquerda é o seu território. A fase abre quando a skill roda em um prompt próprio, e o ArchHook julga cada escrita contra essa lista. O texto à direita é o do próprio hook.
write_allow de sonar-lessons
- ✓
docs/lessons-learned/** qualquer caminho fora desta lista, quando a própria skill abre a fase
A recusa sai com código 2 e a mensagem volta para o modelo.
> /sonar-lessons … UserPromptSubmit guard prompt exit 0 # phase opened: sonar-lessons (class report) # write_allow: docs/lessons-learned/**
PreToolUse Write(docs/lessons-learned/lessons-learned-001.md) guard write exit 0
PreToolUse Write(pom.xml) guard write exit 2 ❌ `sonar-lessons` is class `report` — pom.xml is outside its territory. write_allow: docs/lessons-learned/** Put the content in the spec as a code block, or finish the run and invoke the skill that owns this path. If the path is legitimately this skill's, widen skill_classes.report in .claude/schemas/extensions.json — retrying will not help.
Quem a chama
Não é um passo de uma cadeia. Ela começa em um prompt próprio, /sonar-lessons, e o guard a trata como qualquer outra skill: a fase abre e vale o território da sua classe.