# Desktop Sonar

> Use when fixing SonarCloud issues in apps/desktop or writing Sonar-clean Electron and renderer code. Covers the enforced rule categories, the accepted role=dialog deferral, CSP and page-asset rules, and links the live SonarCloud project.

- Skill: `yosemitecrew/desktop-sonar` (Agent Skill)
- Install (CLI): `npx skillmds@latest add yosemitecrew/desktop-sonar`
- Raw SKILL.md: https://api.skillmd.com/api/skills/yosemitecrew/desktop-sonar/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: yosemitecrew (https://skillmd.com/u/yosemitecrew)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/yosemitecrew/desktop-sonar

---


# Desktop SonarQube Rules — Yosemite Crew

## Description

Use this skill when fixing SonarCloud issues in `apps/desktop`, or when writing new desktop code
that must pass Sonar checks. Covers the rule categories enforced on the desktop project, the
accepted deferral, and the fix patterns — plus where the authoritative issue list lives.

TRIGGER: any mention of "sonar", "code quality", or "lint issues" while working in `apps/desktop`,
or when writing new Electron/renderer code.

> Surface note: this is the Codex/AGENTS copy. Mandatory checks live in `apps/desktop/AGENTS.md`;
> the skill index is in the repo root `AGENTS.md`. The Claude Code copy is `.claude/skills/desktop-sonar/`.

---

## Authoritative Source — Do Not Freeze a Snapshot

The single source of truth for open issues is the **SonarCloud project
`yosemitecrew_Yosemite-Crew_Desktop`**. PR and branch pushes are analyzed in CI by the scan-only
`_sonar` stage of `.github/workflows/ci.yaml`; `.github/workflows/sonar-cloud-analysis.yml` is
the nightly type-aware backstop. The rule mix changes over time, so **check the live
project for the current list** rather than trusting any static dump. This skill documents the
_categories_ and _fix patterns_ that recur on this codebase, not a frozen issue count.

Do not reference the gitignored local-only Sonar tooling in any tracked file — that workflow lives
in the gitignored `CLAUDE.local.md`.

---

## Mandatory Checks — run from `apps/desktop/` after every change

```bash
pnpm run type-check   # tsc (app) + tsc (tests)
pnpm run lint         # eslint .
pnpm run archlint     # local proxy for complexity / cyclic deps / dead code
pnpm test             # full Jest suite (fast here)
```

There is **no `eslint-plugin-sonarjs`** wired into desktop. The local proxy for cognitive /
cyclomatic complexity and dead code is **`archlint`** (`.archlint.yaml`). The authoritative
complexity and smell check is still the SonarCloud analysis.

---

## Coverage gate

Desktop is gated by the same aggregate and PR added-line coverage floors defined in
`.github/workflows/_test.yaml` as the rest of the repo; see
[`docs/ci/coverage.md`](../../../docs/ci/coverage.md) for the full explanation.

Durable caveat (fixed in #2238, kept here so it does not regress): `coverageProvider: 'v8'` needs
source maps to attribute coverage back to your `.ts` sources. `apps/desktop/tsconfig.json` sets
`sourceMap: false`, and only `tsconfig.test.json` overrides it to `true`. Dropping that override
would make v8-to-istanbul report every loaded line as executed, so newly added dead code would
measure as fully covered and neither the added-line nor the aggregate floor could catch it.

Canary check if you suspect the source-map wiring broke: append an exported function nothing calls,
run coverage, and confirm its body reports zero hits. If it shows as covered, the source maps are
off. See the "Running it locally" recipe in that doc.

---

## Accepted Deferral

- **`Web:S6819`** (prefer native `<dialog>` over `role="dialog"`) is **deferred** in
  `src/pages/tabbar.html` where the overlay is shown/hidden via a CSS class or inline-display
  toggle rather than `showModal()`. Converting to a native `<dialog>` would change show/hide
  semantics, so these instances are intentionally left as-is. Do not "fix" them blindly — match
  the existing deferral unless you are also migrating the show/hide mechanism.

---

## Security & Reliability (fix immediately — these are bugs/vulns, not smells)

- **`Web:S7039` — CSP `unsafe-inline`.** Externalize inline `<style>`/`<script>`/`style=""` to
  `.css`/`.js` files; keep `style-src file:; script-src file:;`. **Register every new file in
  `scripts/copy-static.js` `pageAssets`** or it won't ship.
- **`Web:InputWithoutLabelCheck`.** Every input needs an associated `<label>` or an `aria-label`.

---

## TypeScript / JS Rules (with one-line fixes)

| Rule               | Fix                                                                                                                                   |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------- |
| `typescript:S1874` | Deprecated `webContents.goBack()/goForward()` → `webContents.navigationHistory.goBack()/goForward()` (also `canGoBack/canGoForward`). |
| `*:S7764`          | Prefer `globalThis` over bare `window` in renderer page scripts.                                                                      |
| `*:S7761`          | Prefer `.dataset` over `get/set/removeAttribute('data-…')`.                                                                           |
| `*:S6582`          | Optional chaining: `a && a.b` → `a?.b`.                                                                                               |
| `typescript:S6606` | Nullish coalescing: `\|\|` → `??`/`??=` when the left side can be `0`/`''`.                                                           |
| `typescript:S7741` | `=== undefined` over `typeof x === 'undefined'`.                                                                                      |
| `*:S7735`          | Invert unexpected negated conditions (`if(!x){A}else{B}`) or use an early return.                                                     |
| `*:S3358`          | Extract nested ternaries into a named helper.                                                                                         |
| `typescript:S3776` | Cognitive complexity > 15 → extract helper functions.                                                                                 |
| `typescript:S2004` | Functions nested > 4 levels → extract.                                                                                                |
| `typescript:S4325` | Remove unnecessary type assertions.                                                                                                   |
| `typescript:S7748` | No zero-fraction numbers (`1.0` → `1`).                                                                                               |
| `typescript:S6564` | Remove redundant type alias.                                                                                                          |
| `typescript:S6598` | Type literal with only a call signature → function type.                                                                              |
| `typescript:S6551` | Robust error stringify: `error instanceof Error ? error.message : String(error)`.                                                     |
| `typescript:S7754` | `.some()` over `.find()` when the result is used as a boolean.                                                                        |
| `typescript:S2486` | Handle the caught error, or use a paramless `catch {}` for a deliberate ignore.                                                       |
| `typescript:S7780` | `String.raw` for strings containing backslashes.                                                                                      |
| `typescript:S7743` | Avoid a confusing IIFE with a parenthesized arrow body.                                                                               |
| `typescript:S3735` | Remove a stray `void` operator. (`void promise` to satisfy `no-floating-promises` is fine and is **not** what this flags.)            |
| `typescript:S4043` | Copy before sorting: `[...arr].sort()` / `.toSorted()`.                                                                               |

### Modern method preferences

| Rule | Fix |
| --------- | ------------------------------------------------------------------- | --- |
| `*:S6557` | `String.startsWith(...)` over regex/`indexOf` at position 0. |
| `*:S7781` | `String.replaceAll(...)` over global-regex `replace`. |
| `*:S7765` | `.includes()` over `indexOf(…) !== -1`. |
| `*:S7758` | `codePointAt` / `String.fromCodePoint` over the char-code variants. |
| `*:S7767` | `Math.trunc(x)` over `x                                             | 0`. |

> Note: `javascript:S3504` ("declare with `let`/`const`, not `var`") has shown up in volume on
> recent scans of generated/page scripts — replace `var` with `const`/`let`. Always confirm the
> current top rules against the live SonarCloud project before a cleanup sweep.

---

## Gotchas

- `eslint --fix` auto-fixes some of these but **not** CSP, accessibility, or complexity issues —
  fix those by hand.
- After any fix, re-run `pnpm run type-check && pnpm run lint && pnpm run archlint` before marking
  resolved; the final word is the SonarCloud analysis in CI.
- Externalizing a page asset is only half the fix — it must also be added to `copy-static.js`.

