skilldrop-cli 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +413 -0
  3. package/bin/skilldrop.js +338 -0
  4. package/model-routing.json +147 -0
  5. package/package.json +36 -0
  6. package/packs.json +90 -0
  7. package/skills/accessibility-audit/SKILL.md +74 -0
  8. package/skills/accessibility-audit/examples/login-form.md +76 -0
  9. package/skills/accessibility-audit/manifest.json +11 -0
  10. package/skills/accessibility-audit/reference.md +69 -0
  11. package/skills/adr-generator/SKILL.md +49 -0
  12. package/skills/adr-generator/manifest.json +11 -0
  13. package/skills/adr-generator/templates/madr.md +56 -0
  14. package/skills/adr-generator/templates/nygard.md +19 -0
  15. package/skills/ai-usage-report/SKILL.md +111 -0
  16. package/skills/ai-usage-report/examples/weekly-engineering-team.md +133 -0
  17. package/skills/ai-usage-report/manifest.json +11 -0
  18. package/skills/ai-usage-report/scripts/build_report.py +436 -0
  19. package/skills/ai-usage-report/templates/report-per-user.md +42 -0
  20. package/skills/ai-usage-report/templates/report-team-rollup.md +49 -0
  21. package/skills/ai-usage-report/templates/usage-event-schema.md +76 -0
  22. package/skills/api-contract-draft/SKILL.md +69 -0
  23. package/skills/api-contract-draft/manifest.json +11 -0
  24. package/skills/api-contract-draft/reference.md +73 -0
  25. package/skills/api-contract-draft/templates/openapi-skeleton.yaml +148 -0
  26. package/skills/architecture-diagrams/SKILL.md +66 -0
  27. package/skills/architecture-diagrams/examples/aws-three-tier.md +44 -0
  28. package/skills/architecture-diagrams/examples/c4-container-saas.md +51 -0
  29. package/skills/architecture-diagrams/examples/microservices-sequence.md +49 -0
  30. package/skills/architecture-diagrams/manifest.json +28 -0
  31. package/skills/architecture-diagrams/templates/c4-container.puml +31 -0
  32. package/skills/architecture-diagrams/templates/mermaid-aws.md +52 -0
  33. package/skills/architecture-diagrams/templates/mermaid-flowchart.md +37 -0
  34. package/skills/architecture-diagrams/templates/mermaid-sequence.md +39 -0
  35. package/skills/audience-profile/SKILL.md +73 -0
  36. package/skills/audience-profile/manifest.json +11 -0
  37. package/skills/audience-profile/reference.md +175 -0
  38. package/skills/brief-intake/SKILL.md +78 -0
  39. package/skills/brief-intake/manifest.json +11 -0
  40. package/skills/brief-intake/templates/brief-adr.md +41 -0
  41. package/skills/brief-intake/templates/brief-decision-log.md +35 -0
  42. package/skills/brief-intake/templates/brief-deck.md +43 -0
  43. package/skills/brief-intake/templates/brief-design-doc.md +48 -0
  44. package/skills/brief-intake/templates/brief-exec-summary.md +47 -0
  45. package/skills/brief-intake/templates/brief-generic.md +45 -0
  46. package/skills/brief-intake/templates/brief-runbook.md +44 -0
  47. package/skills/brief-intake/templates/brief-tech-comparison.md +38 -0
  48. package/skills/bug-triage/SKILL.md +67 -0
  49. package/skills/bug-triage/manifest.json +11 -0
  50. package/skills/bug-triage/templates/bug-ticket.md +86 -0
  51. package/skills/business-case/SKILL.md +64 -0
  52. package/skills/business-case/manifest.json +11 -0
  53. package/skills/business-case/templates/business-case.md +60 -0
  54. package/skills/capacity-cost-model/SKILL.md +64 -0
  55. package/skills/capacity-cost-model/manifest.json +11 -0
  56. package/skills/capacity-cost-model/reference.md +54 -0
  57. package/skills/capacity-cost-model/templates/cost-model.md +68 -0
  58. package/skills/council-review/SKILL.md +106 -0
  59. package/skills/council-review/examples/redis-cache-decision.md +75 -0
  60. package/skills/council-review/manifest.json +11 -0
  61. package/skills/council-review/reference.md +76 -0
  62. package/skills/council-review/seats/architect.md +29 -0
  63. package/skills/council-review/seats/bench.md +39 -0
  64. package/skills/council-review/seats/operator.md +27 -0
  65. package/skills/council-review/seats/pragmatist.md +29 -0
  66. package/skills/council-review/seats/security-engineer.md +29 -0
  67. package/skills/council-review/seats/user-advocate.md +27 -0
  68. package/skills/council-review/templates/council-review.md +59 -0
  69. package/skills/data-contract/SKILL.md +67 -0
  70. package/skills/data-contract/manifest.json +11 -0
  71. package/skills/data-contract/reference.md +46 -0
  72. package/skills/data-contract/templates/data-contract.md +69 -0
  73. package/skills/db-schema-design/SKILL.md +68 -0
  74. package/skills/db-schema-design/manifest.json +11 -0
  75. package/skills/db-schema-design/reference.md +56 -0
  76. package/skills/db-schema-design/templates/schema-design.md +75 -0
  77. package/skills/decision-log/SKILL.md +67 -0
  78. package/skills/decision-log/manifest.json +11 -0
  79. package/skills/deck-builder/SKILL.md +114 -0
  80. package/skills/deck-builder/examples/exec-board-update.md +108 -0
  81. package/skills/deck-builder/manifest.json +17 -0
  82. package/skills/deck-builder/reference.md +92 -0
  83. package/skills/deck-builder/requirements.txt +1 -0
  84. package/skills/deck-builder/scripts/build_deck.py +309 -0
  85. package/skills/deck-builder/templates/deck-spec.json +97 -0
  86. package/skills/deck-builder/templates/palettes.json +59 -0
  87. package/skills/design-doc/SKILL.md +49 -0
  88. package/skills/design-doc/manifest.json +11 -0
  89. package/skills/design-doc/templates/design-doc.md +98 -0
  90. package/skills/devils-advocate/SKILL.md +142 -0
  91. package/skills/devils-advocate/lenses/adversarial-review.md +88 -0
  92. package/skills/devils-advocate/lenses/edge-cases.md +95 -0
  93. package/skills/devils-advocate/lenses/future-proofing.md +75 -0
  94. package/skills/devils-advocate/lenses/test-coverage.md +90 -0
  95. package/skills/devils-advocate/manifest.json +11 -0
  96. package/skills/devils-advocate/templates/challenge.md +118 -0
  97. package/skills/doc-critique/SKILL.md +119 -0
  98. package/skills/doc-critique/manifest.json +11 -0
  99. package/skills/doc-critique/rubrics/adr.md +36 -0
  100. package/skills/doc-critique/rubrics/decision-log.md +39 -0
  101. package/skills/doc-critique/rubrics/deck.md +45 -0
  102. package/skills/doc-critique/rubrics/design-doc.md +42 -0
  103. package/skills/doc-critique/rubrics/exec-summary.md +41 -0
  104. package/skills/doc-critique/rubrics/generic.md +40 -0
  105. package/skills/doc-critique/rubrics/runbook.md +42 -0
  106. package/skills/doc-critique/rubrics/tech-comparison.md +40 -0
  107. package/skills/doc-critique/templates/critique.md +49 -0
  108. package/skills/exec-summary/SKILL.md +45 -0
  109. package/skills/exec-summary/manifest.json +11 -0
  110. package/skills/exec-summary/templates/exec-summary.md +48 -0
  111. package/skills/feature-implement-loop/SKILL.md +83 -0
  112. package/skills/feature-implement-loop/manifest.json +11 -0
  113. package/skills/figma-diagrams/SKILL.md +85 -0
  114. package/skills/figma-diagrams/manifest.json +35 -0
  115. package/skills/figma-diagrams/reference.md +91 -0
  116. package/skills/figma-diagrams/requirements.txt +1 -0
  117. package/skills/figma-diagrams/scripts/_figma_client.py +71 -0
  118. package/skills/figma-diagrams/scripts/frame_to_mermaid.py +102 -0
  119. package/skills/figma-diagrams/scripts/inspect_file.py +46 -0
  120. package/skills/figma-diagrams/scripts/list_comments.py +35 -0
  121. package/skills/figma-diagrams/scripts/post_comment.py +52 -0
  122. package/skills/figma-diagrams/templates/figjam-import.json +20 -0
  123. package/skills/guide-builder/SKILL.md +76 -0
  124. package/skills/guide-builder/examples/local-setup-guide.md +127 -0
  125. package/skills/guide-builder/manifest.json +11 -0
  126. package/skills/guide-builder/templates/api-reference.md +120 -0
  127. package/skills/guide-builder/templates/design-walkthrough.md +72 -0
  128. package/skills/guide-builder/templates/setup-guide.md +109 -0
  129. package/skills/incident-comms/SKILL.md +68 -0
  130. package/skills/incident-comms/manifest.json +11 -0
  131. package/skills/incident-comms/reference.md +43 -0
  132. package/skills/incident-comms/templates/messages.md +82 -0
  133. package/skills/llm-eval-harness/SKILL.md +73 -0
  134. package/skills/llm-eval-harness/manifest.json +11 -0
  135. package/skills/llm-eval-harness/reference.md +58 -0
  136. package/skills/llm-eval-harness/templates/eval-plan.md +63 -0
  137. package/skills/llm-eval-harness/templates/golden-case.jsonl +5 -0
  138. package/skills/migration-plan/SKILL.md +68 -0
  139. package/skills/migration-plan/manifest.json +11 -0
  140. package/skills/migration-plan/templates/migration-plan.md +68 -0
  141. package/skills/nfr-spec/SKILL.md +63 -0
  142. package/skills/nfr-spec/manifest.json +11 -0
  143. package/skills/nfr-spec/reference.md +74 -0
  144. package/skills/nfr-spec/templates/nfr-spec.md +56 -0
  145. package/skills/observability-plan/SKILL.md +70 -0
  146. package/skills/observability-plan/manifest.json +11 -0
  147. package/skills/observability-plan/reference.md +67 -0
  148. package/skills/observability-plan/templates/observability-plan.md +62 -0
  149. package/skills/okr-cascade/SKILL.md +59 -0
  150. package/skills/okr-cascade/evals/eval_queries.json +12 -0
  151. package/skills/okr-cascade/evals/evals.json +28 -0
  152. package/skills/okr-cascade/manifest.json +11 -0
  153. package/skills/okr-cascade/templates/okr-cascade.md +46 -0
  154. package/skills/postmortem-generator/SKILL.md +65 -0
  155. package/skills/postmortem-generator/manifest.json +11 -0
  156. package/skills/postmortem-generator/templates/postmortem.md +67 -0
  157. package/skills/prd-draft/SKILL.md +62 -0
  158. package/skills/prd-draft/manifest.json +11 -0
  159. package/skills/prd-draft/templates/prd.md +66 -0
  160. package/skills/prfaq/SKILL.md +75 -0
  161. package/skills/prfaq/evals/eval_queries.json +13 -0
  162. package/skills/prfaq/evals/evals.json +32 -0
  163. package/skills/prfaq/manifest.json +11 -0
  164. package/skills/prfaq/templates/prfaq.md +60 -0
  165. package/skills/release-notes/SKILL.md +61 -0
  166. package/skills/release-notes/manifest.json +11 -0
  167. package/skills/release-notes/templates/release-notes.md +83 -0
  168. package/skills/requirements-interview/SKILL.md +61 -0
  169. package/skills/requirements-interview/manifest.json +11 -0
  170. package/skills/requirements-interview/templates/interview-kit.md +63 -0
  171. package/skills/reverse-architecture/SKILL.md +103 -0
  172. package/skills/reverse-architecture/manifest.json +11 -0
  173. package/skills/reverse-architecture/reference.md +150 -0
  174. package/skills/reverse-architecture/templates/description.md +52 -0
  175. package/skills/reverse-architecture/templates/extraction.md +55 -0
  176. package/skills/runbook-generator/SKILL.md +42 -0
  177. package/skills/runbook-generator/manifest.json +11 -0
  178. package/skills/runbook-generator/templates/runbook.md +109 -0
  179. package/skills/slide-outliner/SKILL.md +58 -0
  180. package/skills/slide-outliner/manifest.json +11 -0
  181. package/skills/slide-outliner/templates/deck-outline.md +131 -0
  182. package/skills/sonar-onboard/SKILL.md +170 -0
  183. package/skills/sonar-onboard/manifest.json +11 -0
  184. package/skills/sonar-onboard/reference.md +151 -0
  185. package/skills/sonar-onboard/templates/github-actions-sonar-server.yml.tmpl +50 -0
  186. package/skills/sonar-onboard/templates/github-actions-sonarcloud.yml.tmpl +53 -0
  187. package/skills/sonar-onboard/templates/readme-snippet.md +38 -0
  188. package/skills/sonar-onboard/templates/sonar-project.properties.tmpl +31 -0
  189. package/skills/sonar-review/SKILL.md +220 -0
  190. package/skills/sonar-review/lenses/bugs.md +48 -0
  191. package/skills/sonar-review/lenses/code-smells.md +64 -0
  192. package/skills/sonar-review/lenses/coverage-and-duplication.md +74 -0
  193. package/skills/sonar-review/lenses/security-hotspots.md +56 -0
  194. package/skills/sonar-review/lenses/vulnerabilities.md +52 -0
  195. package/skills/sonar-review/manifest.json +37 -0
  196. package/skills/sonar-review/reference.md +167 -0
  197. package/skills/sonar-review/templates/report.md +84 -0
  198. package/skills/strategy-analysis/SKILL.md +63 -0
  199. package/skills/strategy-analysis/evals/eval_queries.json +13 -0
  200. package/skills/strategy-analysis/evals/evals.json +36 -0
  201. package/skills/strategy-analysis/manifest.json +11 -0
  202. package/skills/success-metrics/SKILL.md +63 -0
  203. package/skills/success-metrics/evals/eval_queries.json +11 -0
  204. package/skills/success-metrics/evals/evals.json +27 -0
  205. package/skills/success-metrics/manifest.json +11 -0
  206. package/skills/success-metrics/templates/metrics-plan.md +55 -0
  207. package/skills/tech-comparison-matrix/SKILL.md +56 -0
  208. package/skills/tech-comparison-matrix/manifest.json +11 -0
  209. package/skills/tech-comparison-matrix/templates/matrix.md +45 -0
  210. package/skills/test-plan-generator/SKILL.md +59 -0
  211. package/skills/test-plan-generator/manifest.json +11 -0
  212. package/skills/test-plan-generator/templates/test-plan.md +83 -0
  213. package/skills/threat-model/SKILL.md +65 -0
  214. package/skills/threat-model/examples/document-upload.md +56 -0
  215. package/skills/threat-model/manifest.json +11 -0
  216. package/skills/threat-model/reference.md +69 -0
  217. package/skills/user-journey-map/SKILL.md +64 -0
  218. package/skills/user-journey-map/evals/eval_queries.json +12 -0
  219. package/skills/user-journey-map/evals/evals.json +30 -0
  220. package/skills/user-journey-map/examples/b2b-saas-onboarding.md +69 -0
  221. package/skills/user-journey-map/manifest.json +11 -0
  222. package/skills/user-journey-map/templates/journey-map.md +47 -0
  223. package/skills/user-story-splitter/SKILL.md +88 -0
  224. package/skills/user-story-splitter/examples/notifications-epic.md +123 -0
  225. package/skills/user-story-splitter/manifest.json +11 -0
  226. package/skills/user-story-splitter/templates/story.md +40 -0
@@ -0,0 +1,50 @@
1
+ name: SonarQube
2
+
3
+ on:
4
+ push:
5
+ branches: [main, master]
6
+ pull_request:
7
+ types: [opened, synchronize, reopened]
8
+
9
+ jobs:
10
+ sonarqube:
11
+ name: Scan + quality gate
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - name: Checkout
15
+ uses: actions/checkout@v4
16
+ with:
17
+ # Full history is required for accurate blame and new-code-period detection.
18
+ fetch-depth: 0
19
+
20
+ # ─── BUILD + TEST + COVERAGE ───────────────────────────────────────────
21
+ # Replace this block with the project's actual build/test commands.
22
+ # The scanner imports the coverage report produced here — if this step
23
+ # doesn't generate it, Sonar reports 0% coverage on new code.
24
+ #
25
+ # Examples:
26
+ # JS/TS: npm ci && npm test -- --coverage
27
+ # Java: mvn -B verify
28
+ # Python: pip install -r requirements.txt && pytest --cov --cov-report=xml
29
+ # Go: go test ./... -coverprofile=coverage.out
30
+ #
31
+ - name: Build, test, and produce coverage
32
+ run: |
33
+ {{BUILD_TEST_COMMAND}}
34
+
35
+ # ─── SCAN ──────────────────────────────────────────────────────────────
36
+ - name: SonarQube scan
37
+ uses: sonarsource/sonarqube-scan-action@v3
38
+ env:
39
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
40
+ SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
41
+
42
+ # ─── QUALITY GATE ──────────────────────────────────────────────────────
43
+ # Fails the job (and therefore the PR check) when the gate fails.
44
+ # Without this step, scans run but never block merge — defeats the point.
45
+ - name: Quality gate
46
+ uses: sonarsource/sonarqube-quality-gate-action@master
47
+ timeout-minutes: 5
48
+ env:
49
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
50
+ SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
@@ -0,0 +1,53 @@
1
+ name: SonarCloud
2
+
3
+ on:
4
+ push:
5
+ branches: [main, master]
6
+ pull_request:
7
+ types: [opened, synchronize, reopened]
8
+
9
+ jobs:
10
+ sonarcloud:
11
+ name: Scan + quality gate
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - name: Checkout
15
+ uses: actions/checkout@v4
16
+ with:
17
+ # Full history is required for accurate blame and new-code-period detection.
18
+ fetch-depth: 0
19
+
20
+ # ─── BUILD + TEST + COVERAGE ───────────────────────────────────────────
21
+ # Replace this block with the project's actual build/test commands.
22
+ # The scanner imports the coverage report produced here — if this step
23
+ # doesn't generate it, SonarCloud reports 0% coverage on new code.
24
+ #
25
+ # Examples:
26
+ # JS/TS: npm ci && npm test -- --coverage
27
+ # Java: mvn -B verify
28
+ # Python: pip install -r requirements.txt && pytest --cov --cov-report=xml
29
+ # Go: go test ./... -coverprofile=coverage.out
30
+ #
31
+ - name: Build, test, and produce coverage
32
+ run: |
33
+ {{BUILD_TEST_COMMAND}}
34
+
35
+ # ─── SCAN ──────────────────────────────────────────────────────────────
36
+ # The SonarCloud action runs the scanner AND waits for the gate, in one step.
37
+ # Host URL defaults to https://sonarcloud.io — do not override unless you
38
+ # know what you're doing.
39
+ - name: SonarCloud scan
40
+ uses: SonarSource/sonarcloud-github-action@master
41
+ env:
42
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
43
+ # GITHUB_TOKEN is used to decorate the PR with findings.
44
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
45
+
46
+ # ─── QUALITY GATE ──────────────────────────────────────────────────────
47
+ # Fails the job (and therefore the PR check) when the gate fails.
48
+ - name: Quality gate
49
+ uses: SonarSource/sonarqube-quality-gate-action@master
50
+ timeout-minutes: 5
51
+ env:
52
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
53
+ SONAR_HOST_URL: https://sonarcloud.io
@@ -0,0 +1,38 @@
1
+ ## Code quality
2
+
3
+ This repo is gated by **{{SONAR_FLAVOR}}** ({{SONAR_FLAVOR}} = `SonarQube` for self-hosted, `SonarCloud` for SaaS). Every push to the default branch and every pull request runs a scan; the PR check fails if the quality gate fails.
4
+
5
+ **What the gate enforces** (Sonar default — tune in the Sonar UI per project):
6
+
7
+ | Condition | Threshold |
8
+ |---|---|
9
+ | New bugs | 0 |
10
+ | New vulnerabilities | 0 |
11
+ | New security hotspots reviewed | 100% |
12
+ | Coverage on new code | ≥ 80% |
13
+ | Duplicated lines on new code | ≤ 3% |
14
+ | Maintainability rating on new code | A |
15
+ | Reliability rating on new code | A |
16
+ | Security rating on new code | A |
17
+
18
+ The gate measures **new code** (since the previous version), not the whole codebase — so existing debt doesn't block your PR, but new debt does.
19
+
20
+ **Required GitHub secrets:**
21
+
22
+ <!-- For SonarQube server, keep both. For SonarCloud, keep only SONAR_TOKEN. -->
23
+ - `SONAR_TOKEN` — project token from {{SONAR_FLAVOR}} (My Account → Security → Generate Token)
24
+ - `SONAR_HOST_URL` — e.g. `https://sonar.company.com` *(SonarQube server only; omit for SonarCloud)*
25
+
26
+ **Run a scan locally** (against the same {{SONAR_FLAVOR}} project):
27
+
28
+ ```bash
29
+ export SONAR_TOKEN=<your-token>
30
+ # SonarQube server only:
31
+ export SONAR_HOST_URL=<your-sonar-host>
32
+ # SonarCloud: omit SONAR_HOST_URL — it defaults to https://sonarcloud.io
33
+ sonar-scanner
34
+ ```
35
+
36
+ Findings appear at:
37
+ - **SonarQube server:** `${SONAR_HOST_URL}/dashboard?id=<project-key>`
38
+ - **SonarCloud:** `https://sonarcloud.io/dashboard?id=<project-key>`
@@ -0,0 +1,31 @@
1
+ # SonarQube project configuration.
2
+ # Host URL and auth token are passed via env vars (SONAR_HOST_URL, SONAR_TOKEN),
3
+ # not committed here — keeps the file portable across forks and local runs.
4
+
5
+ sonar.projectKey={{PROJECT_KEY}}
6
+ sonar.projectName={{PROJECT_NAME}}
7
+ sonar.projectVersion=1.0
8
+
9
+ # SonarCloud ONLY — required, set to your SonarCloud organization key.
10
+ # Delete this line for self-hosted SonarQube server.
11
+ sonar.organization={{ORG_KEY}}
12
+
13
+ # Source layout — comma-separate for multi-language repos.
14
+ sonar.sources={{SOURCES}}
15
+ sonar.tests={{TESTS}}
16
+
17
+ # Encoding (UTF-8 unless the project has a documented exception).
18
+ sonar.sourceEncoding=UTF-8
19
+
20
+ # Coverage report — paths are relative to the repo root.
21
+ # Each language has its own importer; uncomment the one(s) you generate.
22
+ # {{COVERAGE_PROPERTY}}={{COVERAGE_PATH}}
23
+ # TODO: wire up coverage in your test step, then uncomment the line above.
24
+
25
+ # Exclusions — keep the gate honest by skipping generated, vendored, and migration code.
26
+ sonar.exclusions=**/node_modules/**,**/dist/**,**/build/**,**/.next/**,**/__pycache__/**,**/*.generated.*,**/vendor/**,**/migrations/**
27
+ sonar.test.exclusions=**/*.test.*,**/*.spec.*,**/test/**,**/tests/**
28
+ sonar.coverage.exclusions=**/*.test.*,**/*.spec.*,**/test/**,**/tests/**,**/*.stories.*,**/index.{js,ts}
29
+
30
+ # New-code period — issues in code changed since this reference are what the gate enforces.
31
+ # Defaults to "previous_version"; override in the Sonar UI per-project if needed.
@@ -0,0 +1,220 @@
1
+ ---
2
+ name: sonar-review
3
+ description: Run a Sonar scan against the just-changed code on the current branch and produce a structured compliance report — quality-gate verdict (PASS / FAIL), then severity-tagged findings (🟥 blocker / 🟧 critical / 🟨 major / ⚪ minor / ⚪ info) scoped to changed files, each with file:line, the Sonar rule ID, the category (bug / vulnerability / security hotspot / code smell), why it matters, and a concrete fix. Works against both **SonarQube server** (self-hosted) and **SonarCloud** (SaaS) — mode is detected from `sonar-project.properties`. Sister skill to `devils-advocate`, but enforces Sonar's rule catalog and the project's quality gate rather than a hand-rolled lens sweep. Use after writing code, before pushing or opening a PR, when the user says "is this Sonar-compliant?", "run Sonar on this", "will the quality gate pass?", or any pre-merge compliance check.
4
+ ---
5
+
6
+ # sonar-review
7
+
8
+ You run a Sonar scan against the user's just-changed code and produce a structured pre-merge compliance report. The artifact is a markdown review the user acts on — not raw scanner output, not a quiet "scan complete".
9
+
10
+ This skill is the **Sonar-flavored counterpart to [`devils-advocate`](../devils-advocate/SKILL.md)**: same shape (severity-tagged findings, file:line evidence, concrete fixes, verdict on top), but the rules come from Sonar's catalog and the verdict comes from the project's quality gate, not your judgment.
11
+
12
+ Works against both deployment modes — the mode is detected from `sonar-project.properties`, not asked:
13
+
14
+ | Mode | Detection | Host | Token env |
15
+ |---|---|---|---|
16
+ | **SonarQube server** | No `sonar.organization` line | `$SONAR_HOST_URL` (set by user) | `$SONAR_TOKEN` |
17
+ | **SonarCloud** | `sonar.organization=<key>` present | `https://sonarcloud.io` (fixed) | `$SONAR_TOKEN` |
18
+
19
+ The API endpoints are identical between the two — only the host differs. If the user is jumping in cold and the repo isn't wired up, run [`sonar-onboard`](../sonar-onboard/SKILL.md) first.
20
+
21
+ ## How to respond
22
+
23
+ 1. **Detect the mode.** First thing — read `sonar-project.properties` and check for a `sonar.organization=` line:
24
+ - **Present** ⇒ SonarCloud. Host is `https://sonarcloud.io` (don't read `$SONAR_HOST_URL`).
25
+ - **Absent** ⇒ SonarQube server. Host comes from `$SONAR_HOST_URL`.
26
+
27
+ Use the detected mode for every subsequent step. Don't ask the user — the properties file is the source of truth.
28
+
29
+ 2. **Verify the environment before scanning.** Checks differ by mode:
30
+
31
+ | Check | Applies to | If missing |
32
+ |---|---|---|
33
+ | `sonar-project.properties` at repo root | both | Stop. Tell the user to run `sonar-onboard` first — there's no project config to scan against. |
34
+ | `sonar-scanner` on `PATH` | both | Stop. Print the install hint (see step 3). Do not attempt to install it. |
35
+ | `SONAR_TOKEN` env var set | both | Stop. Tell the user to export it from their Sonar account → Security → Tokens. |
36
+ | `SONAR_HOST_URL` env var set | **server only** | Stop. Tell the user to export it (e.g. `export SONAR_HOST_URL=https://sonar.company.com`). |
37
+
38
+ These are non-negotiable. Don't fabricate findings, don't run a partial scan, don't fall back to a local linter — the artifact this skill produces is a *Sonar* report or it's nothing.
39
+
40
+ 3. **Install hint** if `sonar-scanner` is missing — print verbatim, don't drive the install:
41
+
42
+ ```
43
+ sonar-scanner CLI not found on PATH. Install it:
44
+ macOS: brew install sonar-scanner
45
+ Linux: https://docs.sonarsource.com/sonarqube/latest/analyzing-source-code/scanners/sonarscanner/
46
+ Docker: docker run --rm -v "$(pwd):/usr/src" sonarsource/sonar-scanner-cli
47
+ Then re-run this skill.
48
+ ```
49
+
50
+ 4. **Identify the change under review.** Same precedence as `devils-advocate`:
51
+ - User has shown you a diff or named files — that's the scope.
52
+ - Git working tree has unstaged + uncommitted changes — `git diff` is the scope.
53
+ - User says "the feature I just built" — run `git diff origin/main...HEAD` (or `HEAD~1` if no upstream).
54
+
55
+ The scope is the **set of changed files**, not the whole repo. The scan itself runs against the whole project (Sonar needs the full graph for accurate cross-file analysis), but **findings you report are filtered to changed files only** — anything else is out-of-scope noise.
56
+
57
+ 5. **Set the host variable for the run.** Same logic, both modes:
58
+
59
+ ```bash
60
+ if grep -q '^sonar.organization=' sonar-project.properties; then
61
+ SONAR_HOST="https://sonarcloud.io" # SonarCloud is fixed
62
+ else
63
+ SONAR_HOST="$SONAR_HOST_URL" # server reads env var
64
+ fi
65
+ ```
66
+
67
+ Use `$SONAR_HOST` for both the scanner CLI and the API calls below.
68
+
69
+ 6. **Run the scan.** From the repo root:
70
+
71
+ ```bash
72
+ sonar-scanner \
73
+ -Dsonar.host.url="$SONAR_HOST" \
74
+ -Dsonar.token="$SONAR_TOKEN" \
75
+ -Dsonar.branch.name="$(git rev-parse --abbrev-ref HEAD)"
76
+ ```
77
+
78
+ Note on `sonar.branch.name`: SonarCloud accepts it on all tiers; SonarQube Community Edition does not. If you see `License not valid for branch analysis`, drop the flag and re-run — the scan will overwrite the default branch's history (acceptable for a local pre-merge check, not for CI).
79
+
80
+ If the project uses Maven, Gradle, or `dotnet-sonarscanner`, prefer those wrappers (they hook into the compile step) — check `sonar-project.properties` and the build files to decide. See [`reference.md`](reference.md).
81
+
82
+ The scan typically takes 30s–3min. **Wait for it.** Do not summarize before results land — a "should pass" guess is worse than waiting.
83
+
84
+ 7. **Fetch the gate status and issues from the Sonar API.** After the scan finishes, the scanner writes `.scannerwork/report-task.txt` with a `ceTaskUrl` — poll it until `status=SUCCESS`, then fetch (same endpoints for server and cloud — only `$SONAR_HOST` differs):
85
+
86
+ ```bash
87
+ PROJECT_KEY=$(grep '^sonar.projectKey=' sonar-project.properties | cut -d= -f2)
88
+ BRANCH=$(git rev-parse --abbrev-ref HEAD)
89
+
90
+ # Quality gate
91
+ curl -s -u "$SONAR_TOKEN:" \
92
+ "$SONAR_HOST/api/qualitygates/project_status?projectKey=$PROJECT_KEY&branch=$BRANCH"
93
+
94
+ # Issues (scoped to new code in this branch)
95
+ curl -s -u "$SONAR_TOKEN:" \
96
+ "$SONAR_HOST/api/issues/search?componentKeys=$PROJECT_KEY&branch=$BRANCH&inNewCodePeriod=true&ps=500"
97
+
98
+ # Security hotspots
99
+ curl -s -u "$SONAR_TOKEN:" \
100
+ "$SONAR_HOST/api/hotspots/search?projectKey=$PROJECT_KEY&branch=$BRANCH&inNewCodePeriod=true"
101
+ ```
102
+
103
+ Filter the issues list to changed files (compare each issue's `component` field against the diff). See [`reference.md`](reference.md) for the exact JSON shapes.
104
+
105
+ 8. **Map Sonar severities to the report's severity markers.** Keep the mapping consistent across reports:
106
+
107
+ | Sonar severity | Marker | Meaning in the report |
108
+ |---|---|---|
109
+ | `BLOCKER` | 🟥 **Blocker** | Will ship a bug or security issue. Must fix before merge. |
110
+ | `CRITICAL` | 🟧 **Critical** | High-impact bug, hotspot, or vulnerability that needs review before merge. |
111
+ | `MAJOR` | 🟨 **Major** | Code smell or quality issue that will hurt within months. Fix before merge if reasonable. |
112
+ | `MINOR` | ⚪ **Minor** | Quality nit. Fine to defer. |
113
+ | `INFO` | ⚪ **Info** | Optional. List only if there are < 5 of them; otherwise summarize the count. |
114
+
115
+ **Do not invent severity.** Sonar's catalog assigns it — copy it. The mapping is mechanical, not judgmental.
116
+
117
+ 9. **Sweep the five lenses.** Sonar categorizes every finding into one of these — group the report by lens, same as `devils-advocate`. Each lens file describes what to look for and how to phrase the fix:
118
+
119
+ | Lens | File | Sonar issue type |
120
+ |---|---|---|
121
+ | 1. Bugs | [`lenses/bugs.md`](lenses/bugs.md) | `BUG` |
122
+ | 2. Vulnerabilities | [`lenses/vulnerabilities.md`](lenses/vulnerabilities.md) | `VULNERABILITY` |
123
+ | 3. Security hotspots | [`lenses/security-hotspots.md`](lenses/security-hotspots.md) | `SECURITY_HOTSPOT` (separate API) |
124
+ | 4. Code smells | [`lenses/code-smells.md`](lenses/code-smells.md) | `CODE_SMELL` |
125
+ | 5. Coverage + duplication | [`lenses/coverage-and-duplication.md`](lenses/coverage-and-duplication.md) | Quality-gate condition failures |
126
+
127
+ 10. **For every finding, write four parts** (same shape as `devils-advocate`):
128
+
129
+ - **Where:** `file:line` — quote 5–15 chars of the offending line.
130
+ - **Rule + category:** `[BUG · javascript:S2228] Console logging should not be used`. The rule ID is what the user clicks in the Sonar UI to read the catalog page.
131
+ - **Why it matters:** one sentence — what the rule prevents *in this scenario*. ✅ "Mutable shared state in `parseConfig` will desync between requests under concurrent load." ❌ "Avoid shared state."
132
+ - **Fix:** ✅ "Wrap the cache in `Object.freeze()` on line 23, or move the mutable copy inside `parseConfig` (preferred — matches the pattern in `parseUserConfig`:51)." ❌ "Refactor to avoid mutation."
133
+
134
+ 11. **Open with the gate verdict, not the findings.** The first thing the user sees:
135
+
136
+ ```
137
+ Quality gate: ❌ FAIL — coverage on new code is 71% (gate requires ≥ 80%), 1 new vulnerability.
138
+ Findings on changed code: 1 blocker · 3 critical · 7 major · 4 minor.
139
+
140
+ The blocker is a SQL-injection-shaped query construction at api/users.ts:142 (rule javascriptsecurity:S3649) — parameterize before merging. The vulnerability and the coverage shortfall are what's failing the gate; the major findings are all in the new payment-handler module and are fixable with the patterns used elsewhere in the codebase.
141
+ ```
142
+
143
+ If the gate passed, lead with that and still report findings (a passing gate doesn't mean zero issues — it means the *new code* met the conditions; minor findings may still be worth fixing).
144
+
145
+ 12. **Use [`templates/report.md`](templates/report.md)** for the output structure:
146
+
147
+ ```markdown
148
+ # Sonar review: {feature / PR title}
149
+ _Scope: {N changed files} · Branch: {branch} · Scanned: {YYYY-MM-DD HH:MM}_
150
+ _Sonar project: [{project-key}]({sonar-url}/dashboard?id={project-key}&branch={branch})_
151
+
152
+ ## Quality gate
153
+ {PASS / FAIL} — {one-line reason}
154
+ {2-sentence summary, lead with what failed the gate}
155
+
156
+ ## Findings on changed code
157
+ {counts table}
158
+
159
+ ### 1. Bugs
160
+ ### 2. Vulnerabilities
161
+ ### 3. Security hotspots
162
+ ### 4. Code smells
163
+ ### 5. Coverage + duplication
164
+
165
+ ## Pre-existing issues touched (FYI)
166
+ {issues in files you changed that pre-date this branch — for awareness, not blocking}
167
+
168
+ ## Suggested order to address
169
+ 1. Fix anything failing the quality gate (blockers + vulnerabilities + coverage)
170
+ 2. Review the security hotspots — Sonar can't auto-decide, you have to mark them
171
+ 3. Major findings, especially anything in load-bearing or security-adjacent code
172
+ 4. Minors as time allows
173
+ ```
174
+
175
+ 13. **End with the Sonar dashboard link.** The full picture — including pre-existing debt, history, and the gate's detailed conditions — lives in the Sonar UI. Always end with `Full report: ${SONAR_HOST}/dashboard?id=<project-key>&branch=<branch>` — `$SONAR_HOST` is the value you set in step 5 (so the link works whether the project is on SonarQube server or SonarCloud).
176
+
177
+ ## Useful references in this skill
178
+
179
+ - [`lenses/bugs.md`](lenses/bugs.md) — how to phrase Bug findings
180
+ - [`lenses/vulnerabilities.md`](lenses/vulnerabilities.md) — Vulnerability findings (CWE / OWASP-tagged)
181
+ - [`lenses/security-hotspots.md`](lenses/security-hotspots.md) — Hotspots need human review, not auto-fix
182
+ - [`lenses/code-smells.md`](lenses/code-smells.md) — Maintainability findings
183
+ - [`lenses/coverage-and-duplication.md`](lenses/coverage-and-duplication.md) — Gate conditions that aren't issues
184
+ - [`templates/report.md`](templates/report.md) — Report skeleton
185
+ - [`reference.md`](reference.md) — Sonar API shapes, Maven/Gradle/dotnet variants, scoping to PR diffs
186
+
187
+ ## Quality bar
188
+
189
+ - **Verdict comes from the gate, not from you.** The quality gate is the source of truth. ✅ "Gate FAIL — 1 new vulnerability." ❌ "Looks risky to me." If the gate passed, say PASS even if you'd personally flag issues.
190
+ - **Findings are scoped to changed files.** The repo has pre-existing debt; this skill is a pre-merge check, not a backlog dump. Pre-existing issues in *touched* files go in a separate "FYI" section — issues in untouched files don't appear at all.
191
+ - **Every finding cites `file:line` and the Sonar rule ID.** `javascript:S2228` is a click-through to the Sonar UI catalog. Strip either and the finding becomes unactionable.
192
+ - **Severity is Sonar's, not yours.** Don't downgrade a `CRITICAL` because you disagree, and don't upgrade a `MINOR` to make the report scarier. If you disagree with the catalog, raise it in the lens body, don't rewrite the severity.
193
+ - **Fixes name a concrete change.** A patch line, a function rename, a missing test case — not "consider refactoring".
194
+ - **Don't recommend disabling rules to pass the gate.** That's a code-quality conversation. Suggest fixes or scoping (Sonar-scoping comments like `// NOSONAR` should be rare and justified in the code, not as a default).
195
+ - **Security hotspots are flagged for review, not "fixed".** Hotspots ask "is this safe?" — the resolution is a human decision (mark Safe, At Risk, Acknowledged). The fix you write is *the evidence the user needs to make that call*, not a code patch.
196
+
197
+ ## When to use this skill
198
+
199
+ - ✅ After implementing a feature, before opening a PR ("is this Sonar-compliant?")
200
+ - ✅ When CI shows a failed Sonar gate and the user wants the findings explained locally before pushing again
201
+ - ✅ Before merging a long-lived branch back to main — final gate check
202
+ - ✅ Sanity check after rebasing onto main, to catch newly-applied rules
203
+
204
+ ## When NOT to use this skill
205
+
206
+ - ❌ Repo isn't set up for Sonar (no `sonar-project.properties`). Run `sonar-onboard` first.
207
+ - ❌ User wants a code review broader than Sonar's catalog covers (architecture, idiomatic concerns, test-design). Use `devils-advocate` instead — different lens.
208
+ - ❌ User wants to fix the *whole codebase*'s Sonar debt. This skill is per-change; for a debt-paydown plan, query the Sonar UI directly.
209
+ - ❌ Repo only has linters (ESLint, Pylint, golangci-lint) and no Sonar. Different tool, different catalog — running this skill would produce nothing.
210
+ - ❌ Repo isn't wired to *either* SonarQube server or SonarCloud — no `sonar-project.properties` means there's nothing to scan against. Run `sonar-onboard` first.
211
+
212
+ ## Anti-patterns to avoid
213
+
214
+ - ❌ **Guessing the gate result.** Always wait for the actual scan + API call. A "should pass" prediction without the scan is the worst possible output — it builds false confidence.
215
+ - ❌ **Reporting issues from untouched files.** The user opened a PR for one feature; flooding them with debt from other files is noise. Scope strictly to changed files; pre-existing-in-touched-files go in the FYI section.
216
+ - ❌ **Translating rule IDs into prose.** Keep `javascript:S2228` literal — that's the click-through key. ❌ "Use of console logging" ✅ "[javascript:S2228] Use of console logging".
217
+ - ❌ **Suggesting `// NOSONAR` as the default fix.** That's "make the linter shut up", not compliance. Reserve for documented exceptions with a comment explaining why.
218
+ - ❌ **Auto-fixing the code.** This skill produces a *report*. The user (or another agent / skill) decides what to change. Auto-fixes hide the learning and the audit trail.
219
+ - ❌ **Hiding the FAIL.** If the gate fails, lead with FAIL. Don't bury it under "but here's what's good" — the user opened this skill to know whether they can merge.
220
+ - ❌ **Treating security hotspots as bugs.** Hotspots are *review-required*; the resolution is human judgment. Show the evidence, then ask the user to mark Safe / At Risk / Acknowledged — don't patch them silently.
@@ -0,0 +1,48 @@
1
+ # Lens 1 — Bugs
2
+
3
+ Sonar's **Bug** category is code that is **demonstrably broken or will break**: null dereferences, off-by-one, dead branches, resource leaks, race-shaped APIs, contracts that don't hold. Bugs are the highest-signal lens — every bug is, by Sonar's definition, a defect waiting to ship.
4
+
5
+ ## What you're looking at
6
+
7
+ Pull the issues list, filter to `type=BUG`, then filter further to the changed-files set. Common bug rules to recognize on sight:
8
+
9
+ | Rule family | Example IDs | What it catches |
10
+ |---|---|---|
11
+ | Null dereference | `javascript:S2259`, `java:S2259`, `python:S5713`, `csharpsquid:S2259` | `x.foo` where `x` can be null/None |
12
+ | Off-by-one / loop bound | `S2440`, `S2189`, `S2583` | `<=` vs `<`, infinite loops, dead branches |
13
+ | Resource leak | `S2095`, `S2093` | unclosed streams, files, DB connections |
14
+ | Exception handling | `S2737`, `S108`, `S1166` | empty catch, swallowed throwables, `throw` lost in finally |
15
+ | Equality / comparison | `S2159`, `S1698`, `S3403` | `==` on incompatible types, `equals` vs `==` |
16
+ | Floating-point comparison | `S1244` | `if (x == 0.1)` |
17
+ | Date / time | `S3725`, `S6353` | wrong timezone, deprecated `Date` mutation |
18
+ | Promise / async (JS/TS) | `S4123`, `S6544` | unawaited promises, missing error handlers |
19
+ | Mutable shared state | `S2386`, `S3008` | non-final static, mutable singletons |
20
+
21
+ If the rule isn't in this list, look it up at `${SONAR_HOST_URL}/coding_rules?open=<rule-id>` — Sonar links every issue to its catalog page with examples.
22
+
23
+ ## How to phrase each finding
24
+
25
+ Four parts, same as the report skeleton:
26
+
27
+ 1. **Where** — `file:line` + a 5–15 char quote of the offending code.
28
+ 2. **Rule + category** — `[BUG · javascript:S2259] Null dereference` — keep the rule ID literal.
29
+ 3. **Why it matters** — name the **runtime scenario**, not the rule. ✅ "When `req.body.discount` is omitted from the request, `discount.amount` throws `TypeError: Cannot read properties of undefined` — the endpoint 500s." ❌ "Possible null dereference."
30
+ 4. **Fix** — concrete. Either:
31
+ - **Paste-able patch** — a one-line guard, a `??`, an `if (x == null) return`, a `try/finally`. Quote the line numbers.
32
+ - **Pattern reference** — "Use the `withConnection` helper from `db.ts:14` instead of opening directly; it handles the `finally` close."
33
+
34
+ ## Calibration
35
+
36
+ - **BLOCKER bug** ≈ ships a defect on the happy path or a security-shaped fault (e.g. unsanitized `eval`, SQL string concat). Treat as merge-blocking.
37
+ - **CRITICAL bug** ≈ defect on a common error path (null on optional field, leak on retry). Fix before merge.
38
+ - **MAJOR bug** ≈ defect on an uncommon path (rare race, edge encoding). Fix or file a follow-up issue.
39
+ - **MINOR bug** is rare for the Bug category — usually means Sonar isn't sure. Verify before reporting.
40
+
41
+ Trust Sonar's severity here; the Bug catalog is the most-calibrated of the five lenses.
42
+
43
+ ## Anti-patterns when reporting Bugs
44
+
45
+ - ❌ Restating the rule name as the "why". The rule name is in the catalog — your job is the *scenario* in this codebase.
46
+ - ❌ Fixing the symptom not the cause. ❌ "Wrap in try/catch and log." ✅ "The caller passes `null` from `getDiscount` when no promo applies — change `getDiscount` to return `{amount: 0}` instead of null, then this site needs no guard."
47
+ - ❌ Down-grading a BLOCKER because it "looks fine to you". The bug catalog is mechanical — if Sonar caught a null deref, there's a path to it. Find the path or trust the rule.
48
+ - ❌ Recommending `// NOSONAR` as the fix. Reserve that for documented exceptions; it's never the right answer for a Bug.
@@ -0,0 +1,64 @@
1
+ # Lens 4 — Code Smells
2
+
3
+ The **maintainability** lens. Code smells aren't bugs or security issues — they're patterns Sonar predicts will slow future change. The catalog is large and noisy; this lens is where over-reporting hurts the report most.
4
+
5
+ ## What you're looking at
6
+
7
+ Filter issues to `type=CODE_SMELL` and changed files. Common families on new code:
8
+
9
+ | Family | Example IDs | Worth reporting on changed code? |
10
+ |---|---|---|
11
+ | Cognitive complexity | `S3776` | ✅ Yes — predictive of bugs |
12
+ | Function / method length | `S138`, `S104` | ✅ Yes — but often a refactor target, not a one-line fix |
13
+ | Parameter count | `S107` | ✅ Yes |
14
+ | Duplicated string literals | `S1192` | 🟨 Maybe — only if literal is meaningful (URL, key) |
15
+ | Magic numbers | `S109` | 🟨 Maybe — extract a constant if used > 2 places |
16
+ | Unused imports / variables | `S1481`, `S1128` | ✅ Yes — trivial fix |
17
+ | Empty methods / classes | `S1186`, `S1186` | ✅ Yes |
18
+ | TODO / FIXME comments | `S1135` | ⚪ Info — surface in count, don't list each |
19
+ | Naming conventions | `S100`, `S116` | 🟨 Only flag if the new identifier breaks the project's pattern |
20
+ | `console.log` / `print` | `S2228`, `S1854` | ✅ Yes if not behind a logger |
21
+ | Deprecated API use | `S1874` | ✅ Yes |
22
+ | Commented-out code | `S125` | 🟨 Maybe — sometimes intentional (TODO + commented call) |
23
+
24
+ The principle: **report what's actionable in this PR, summarize what isn't**. A finding the user can fix in five minutes is worth a line; a refactor finding that requires opening four files is worth one line in summary form.
25
+
26
+ ## How to phrase each finding
27
+
28
+ Standard four parts:
29
+
30
+ 1. **Where** — `file:line` + a quote.
31
+ 2. **Rule + category** — `[SMELL · typescript:S3776] Cognitive complexity 22 > 15`.
32
+ 3. **Why it matters** — the *future-maintenance* cost, in concrete terms. ✅ "`processOrder` has six nested conditionals; the next person debugging a refund flow has to trace all six to know which branch they're in." ❌ "Code is too complex."
33
+ 4. **Fix** — concrete:
34
+ - Complexity → extract one of the conditional branches into a named function. Suggest the name.
35
+ - Long parameter list → struct/object parameter. Name the fields.
36
+ - Magic number → name the constant. Suggest the name and the scope (file-level vs class-level).
37
+ - Duplicated literal → suggest the constant name + the line numbers that should reference it.
38
+
39
+ ## Calibration
40
+
41
+ Sonar's severity on code smells is **less reliable** than on bugs/vulns — the same `S3776` is CRITICAL when complexity is 30 and MAJOR when it's 16. Trust the severity, but don't expect every CRITICAL smell to actually block merge.
42
+
43
+ | Severity | Treat as |
44
+ |---|---|
45
+ | 🟥 BLOCKER | Rare for smells; usually means complexity is extreme (>25). Treat as merge-blocker. |
46
+ | 🟧 CRITICAL | High-cost smell on load-bearing code. Fix before merge. |
47
+ | 🟨 MAJOR | Most common smell severity. Fix if cheap; defer if the refactor is large. |
48
+ | ⚪ MINOR | Style + naming. Roll up into a count if there are > 5. |
49
+
50
+ ## Aggregation rule
51
+
52
+ If the new code has more than **8 minor code smells of the same rule** (e.g. 12 magic numbers in one file), don't list each — emit one rolled-up finding:
53
+
54
+ > 🟨 **`typescript:S1192` — String literal duplication × 12** in `src/api/orders.ts`. The literal `"USD"` appears 12 times across `createOrder`, `applyDiscount`, and `formatTotal`. Extract `const CURRENCY = "USD"` at the top of the file and reference it from each site.
55
+
56
+ Don't bury single-instance findings in rollups — only roll up repeats of the same rule in the same area.
57
+
58
+ ## Anti-patterns when reporting Code Smells
59
+
60
+ - ❌ **Listing every smell**. The report becomes unreadable. Prioritize, aggregate, summarize the tail.
61
+ - ❌ **Recommending a rename as the fix for a complexity smell.** Renaming doesn't reduce complexity. Extract a function or flip a guard clause.
62
+ - ❌ **Flagging style on a PR that fixes a bug.** If the change is a targeted bug fix and the smells are pre-existing in the same function, those go in the "pre-existing issues touched" FYI section, not the main report.
63
+ - ❌ **Treating `S1192` (string duplication) as serious in tests.** Tests are *supposed* to repeat literals — that's how you read them. If Sonar flags `"alice"` appearing 8 times across tests, downgrade to nit or drop.
64
+ - ❌ **Confusing "long function" with "complex function".** A 200-line function with no branching is fine; a 30-line function with seven nested `if`s is the smell. Cite `S3776` (cognitive complexity), not `S138` (length), when complexity is the real issue.
@@ -0,0 +1,74 @@
1
+ # Lens 5 — Coverage + Duplication
2
+
3
+ These aren't "issues" in Sonar's data model — they're **quality-gate conditions** measured against the project's new code. They're reported in the gate's `conditions` array, not the issues list. They're often what fails an otherwise-clean gate.
4
+
5
+ ## Coverage on new code
6
+
7
+ Sonar measures *lines and branches added or modified in this branch*. A file that wasn't touched contributes nothing to the new-code coverage metric; touching it forces the touched lines into the measurement.
8
+
9
+ **Default gate condition:** ≥ 80% coverage on new code.
10
+
11
+ ### What to report
12
+
13
+ Fetch the gate JSON, find conditions where `metricKey=new_coverage` and `status=ERROR`. Then drill into:
14
+
15
+ ```bash
16
+ curl -s -u "$SONAR_TOKEN:" \
17
+ "$SONAR_HOST_URL/api/measures/component_tree?component=$PROJECT_KEY&branch=$BRANCH&metricKeys=new_uncovered_lines,new_lines_to_cover&qualifiers=FIL"
18
+ ```
19
+
20
+ Identify the files dragging the percentage down. Report:
21
+
22
+ > ❌ **Coverage on new code: 71%** (gate requires ≥ 80%)
23
+ > - `src/jobs/export.ts` — 47/82 new lines covered (57%). Uncovered: error paths at lines 55–62 and 71–78.
24
+ > - `src/api/checkout.ts` — 31/40 new lines covered (78%). Uncovered: the new `null discount` branch at line 47.
25
+ >
26
+ > **Fix:** Add three tests covering the error paths in `export.ts` and the null-discount branch in `checkout.ts`. The happy path is already covered.
27
+
28
+ ### Naming the missing tests
29
+
30
+ Don't say "add tests" — name them. ✅ "Add a test `it('returns empty when upstream API 500s', ...)` covering `export.ts:55–62`." ❌ "Improve test coverage."
31
+
32
+ If you can't name the missing test scenario, the coverage finding isn't actionable — you don't understand the uncovered branch well enough to flag it as a finding. Drop it and let the gate fail until the user adds the case themselves.
33
+
34
+ ### When coverage looks worse than it is
35
+
36
+ - **Tests in changed dirs not running.** The coverage tool ran but didn't include the new tests. Symptom: 0% on a file that clearly has tests beside it. Check `sonar.tests` and the coverage report path in `sonar-project.properties`.
37
+ - **Coverage exclusions stripped the wrong files.** Symptom: clearly-covered file shows uncovered. Check `sonar.coverage.exclusions`.
38
+ - **Generated files counted.** Symptom: lots of "uncovered" in `__generated__` or `dist/`. Add to `sonar.exclusions`.
39
+
40
+ If you suspect a config issue, **say so explicitly** rather than reporting the bad number as fact: "Coverage shows 0% on `src/payments/`, but `payments.test.ts` exists at the same level — the coverage importer may not be picking up the report. Check `sonar.javascript.lcov.reportPaths` in `sonar-project.properties`."
41
+
42
+ ## Duplication
43
+
44
+ **Default gate condition:** ≤ 3% duplicated lines on new code.
45
+
46
+ Duplication catches copy-paste — a block of ≥ 100 tokens (≈ 10 lines for most languages) that appears more than once. The catalog rule is `common-{language}:DuplicatedBlocks`.
47
+
48
+ ### What to report
49
+
50
+ For each duplication block on changed code:
51
+
52
+ > 🟨 **Duplication: `src/api/checkout.ts:47–78` duplicates `src/api/refund.ts:32–63`** (32 lines, 89% match).
53
+ >
54
+ > The discount-application logic is now copied across both endpoints — the next change to discount handling has to be made twice. Extract `applyDiscount` into `src/lib/discounts.ts` and call it from both.
55
+
56
+ If duplication is *within* the same file, treat it as a single-file refactor — extract a helper at the file top.
57
+
58
+ If duplication is *between* a new file and an existing one, the fix usually means modifying the existing file too. Flag this explicitly — the user may have been told not to touch the other file. Suggest the extraction location, then let them decide.
59
+
60
+ ### When duplication is intentional
61
+
62
+ Sometimes duplication is correct — test fixtures, parallel implementations across services, migration scripts that intentionally mirror old code. If you can see this is the case (e.g. the duplicated code is in `tests/` or named `migrate_*`), say so:
63
+
64
+ > 🟨 **Duplication: `tests/checkout.test.ts:47–78` duplicates `tests/refund.test.ts:32–63`**.
65
+ >
66
+ > The two tests share setup. This is the common-fixture case — extract `setupTestOrder()` into `tests/_helpers.ts`. Not a quality-gate blocker (tests are excluded by default in `sonar.coverage.exclusions` but counted for duplication unless excluded explicitly).
67
+
68
+ ## Anti-patterns when reporting Coverage / Duplication
69
+
70
+ - ❌ **Reporting the percentage without the files dragging it.** "Coverage is 71%" isn't actionable. Name the under-covered files and the uncovered branches.
71
+ - ❌ **Demanding 100% coverage** on the new code. The gate asks for 80% (or whatever the project sets); 100% is rarely worth the test brittleness.
72
+ - ❌ **Demanding tests for log statements / pass-through error paths.** Coverage of a `console.log(...)` line teaches nothing. Suggest the *meaningful* missing scenarios.
73
+ - ❌ **Treating duplication in tests as urgent.** Test fixtures often repeat; the refactor is "nice to have", not gate-blocking, and Sonar agrees if `sonar.cpd.exclusions` is set on `**/*.test.*`.
74
+ - ❌ **Telling the user to disable the gate condition.** The fix is more tests or a small refactor, not weakening the gate. If 80% is structurally impossible for this project, raise it as a separate gate-tuning conversation, not a per-PR finding.
@@ -0,0 +1,56 @@
1
+ # Lens 3 — Security Hotspots
2
+
3
+ Hotspots are the lens most agents get wrong. They are **not** vulnerabilities. They are **security-sensitive code patterns Sonar can't auto-decide are safe** — the resolution is a *human security review*, recorded in Sonar as **Safe**, **At Risk**, or **Acknowledged**.
4
+
5
+ Hotspots come from a **different API** (`/api/hotspots/search`) than Issues. The quality gate counts unresolved hotspots — so an un-reviewed hotspot fails the gate even if the code is secure.
6
+
7
+ ## What you're looking at
8
+
9
+ | Family | Example IDs | What it catches |
10
+ |---|---|---|
11
+ | Cryptographic operations | `S4426`, `S2278` | Use of crypto APIs (could be configured weakly) |
12
+ | Random number generation | `S2245` | `Math.random()` / `Random` — fine for UI, dangerous for tokens |
13
+ | Regex DoS | `S5852` | Catastrophic backtracking patterns |
14
+ | File permissions | `S2612` | World-writable file creation |
15
+ | Authentication / authorization | `S5332` | TLS disabled, `verify=False`, `--insecure` |
16
+ | User-controlled file paths | `S2083` (sometimes Hotspot) | Where validation might be present |
17
+ | Hardcoded IPs / CIDR | `S1313` | Could be a test fixture, could be a backdoor |
18
+ | Cookie / session config | `S2092`, `S3330` | Missing flags Sonar can't verify in context |
19
+ | HTTP method overrides | `S5122` | CORS / `_method` rewriting |
20
+ | Command execution | `S4721` | `exec`-shaped calls (may be safe with constants) |
21
+
22
+ ## How to phrase each Hotspot finding
23
+
24
+ This lens has **five** parts, not four — because the artifact you produce isn't "fix this", it's "evidence for the user to make a decision":
25
+
26
+ 1. **Where** — `file:line` + the sensitive call. Quote 5–15 chars.
27
+ 2. **Rule + category** — `[HOTSPOT · javascript:S2245] Pseudorandom generator use`.
28
+ 3. **Why it's flagged** — what *category* of risk Sonar is asking about. ✅ "`Math.random()` is fine for UI shuffling but unsafe for security tokens." ❌ "Insecure RNG."
29
+ 4. **Evidence for review** — what *this codebase* tells you about whether the usage is actually risky. Quote the surrounding context:
30
+ - Where does the value flow next? (logged? sent? stored? returned to user?)
31
+ - Are there upstream guards? Quote them with `file:line`.
32
+ - Is this test/dev-only code? Quote the file path or test scaffolding around it.
33
+ 5. **Action** — name the **resolution the user should record in Sonar**, with the reasoning they should paste into the resolution comment:
34
+ - **Safe** — quote the upstream guard or the non-security usage that makes it OK.
35
+ - **At Risk** — name the path you can't rule out + the code fix.
36
+ - **Acknowledged** — for known issues with a tracked follow-up. Include the ticket reference.
37
+
38
+ ## Calibration
39
+
40
+ Hotspots don't carry the BLOCKER/CRITICAL/MAJOR severities issues do — they have a **review priority** (`HIGH`/`MEDIUM`/`LOW`) and a **status** (`TO_REVIEW`/`REVIEWED`). Map to your report:
41
+
42
+ | Hotspot priority | Report marker |
43
+ |---|---|
44
+ | HIGH | 🟧 |
45
+ | MEDIUM | 🟨 |
46
+ | LOW | ⚪ |
47
+
48
+ Group hotspots in their own section — don't intermix with bugs/vulnerabilities. They're a different shape of finding.
49
+
50
+ ## Anti-patterns when reporting Hotspots
51
+
52
+ - ❌ **Treating Hotspots like Vulnerabilities.** A Hotspot isn't a defect — it's a question. Reporting "fix this insecure RNG" when the value flows to a UI shuffle is wrong; the answer is "mark Safe with this evidence."
53
+ - ❌ **Recommending a code patch without naming the resolution.** A code patch alone doesn't clear the hotspot in Sonar — the user still needs to mark it Reviewed. Always include "and mark `<status>` in the Sonar UI with the evidence above".
54
+ - ❌ **Skipping the evidence step.** "Looks fine to me" isn't actionable. Quote the upstream guard or the test-only usage that lets the user click Safe with confidence.
55
+ - ❌ **Marking everything At Risk to be cautious.** If the evidence is "no upstream guard, flows to user output", say At Risk. If the evidence is "constant string from build config, never user-influenced", say Safe. Hedging defeats the workflow.
56
+ - ❌ **Forgetting that un-reviewed hotspots fail the gate.** Even a clearly-safe hotspot fails the gate until reviewed. Tell the user explicitly: "marking this Safe is what unblocks the gate — not a code change."