## Linked issue
Follow-up to #5498, which was closed in favor of a smaller and more
maintainable implementation.
## Summary / motivation
Run CI-based SonarCloud analysis for internal and fork pull requests
while keeping the Quality Gate informational.
The analysis matrix is:
| Event | Static analysis | Coverage in CI | Coverage in SonarCloud |
| --- | --- | --- | --- |
| Internal pull request | Yes | Yes | Yes |
| Push to `main` or `release/**` | Yes | Yes | Yes |
| Fork pull request | Yes | Yes | No |
Fork pull requests continue to run the full test coverage and
coverage-regression checks in the unprivileged CI workflow. Their
contributor-produced coverage reports are not passed to the privileged
SonarCloud workflow.
The fork scan reports static bugs, vulnerabilities, security hotspots,
and code smells. It:
- validates the PR state, repositories, branches, and tested SHA against
the GitHub API;
- checks out the exact revision tested by CI;
- replaces `sonar-project.properties` with the trusted default-branch
version;
- provides `SONAR_TOKEN` only to the scanner step;
- never builds, installs, or executes contributor code;
- keeps scanner-side Clippy and SCA disabled;
- clears coverage report paths and excludes coverage calculation for
forks.
Automatic Analysis remains disabled because it cannot be combined with
CI-based analysis and does not provide the required Rust and coverage
support.
This also configures Vitest to produce repository-relative LCOV paths
such as `SF:ts/lib/...`, allowing SonarCloud to resolve TypeScript files
when reports are downloaded into a separate checkout.
## How to test
### Checklist
- [x] I ran `just check` or an equivalent relevant check locally.
- [ ] I added or updated tests when the change is non-trivial or
behavior changed. The remaining behavior is specific to GitHub's
`workflow_run` environment and can only be exercised end-to-end after
the workflow is available on the default branch.
### Details
The following checks passed locally:
- `just test-ts --coverage`
- `just test-ts --coverage --html`
- `just fmt`
- `just check`
- YAML and JSON parsing
- `git diff --check`
Both TypeScript coverage runs passed all 67 tests. The generated LCOV
report was also checked to confirm that source paths are
repository-relative and begin with `SF:ts/`.
After this lands, end-to-end validation should cover:
1. A push to `main`, confirming that Python, TypeScript, and Rust
coverage reports are imported.
2. An internal PR, confirming static analysis and coverage.
3. A fork PR, confirming static analysis while the coverage download is
skipped and no coverage condition is evaluated.
## Before / after behavior
Before:
- fork PR analysis fails at the protected checkout;
- the `actions/checkout` version comments are outdated;
- TypeScript LCOV paths are relative to `ts/` and may not resolve in the
SonarCloud checkout.
After:
- internal PRs and trusted branch pushes receive static analysis and
coverage;
- fork PRs receive static analysis without importing
contributor-produced coverage;
- fork tests and coverage-regression checks continue to run in regular
CI;
- TypeScript LCOV paths resolve from the repository root;
- technical scanner failures remain visible without making the Sonar
Quality Gate a required merge check.
## Risk / compatibility / migration
The fork analysis runs in a privileged `workflow_run` and necessarily
asks the SonarScanner to parse untrusted source while it has access to a
project-scoped token.
The workflow limits this exposure by using GitHub-hosted runners,
read-only permissions, trusted scanner configuration, an exact tested
SHA, API-validated PR metadata, and no builds, dependency installation,
local Actions, caches, or fork-produced coverage artifacts.
This is intentionally a smaller trust boundary than the data-only
snapshot and custom coverage parser proposed in #5498. It prevents
direct execution of contributor code but does not eliminate potential
vulnerabilities in GitHub Actions or Sonar analyzers.
Automatic Analysis must remain disabled, `SONAR_TOKEN` should remain
restricted to this project, and the SonarCloud check must remain
non-required.
## Linked issue
Closes#5521
## Summary / motivation
Adds an Anki-focused unit testing guide for maintainers, contributors,
and coding assistants.
The guide:
- Defines principles for focused, deterministic, and maintainable tests.
- Covers happy paths, error paths, boundaries, regressions, and
test-first development.
- Provides guidance for Python, Python/Qt, Rust, and
Svelte/TypeScript/JavaScript.
- Clarifies the appropriate scope for UI tests and discourages testing
styling or volatile presentation details.
- Links the guide from the shared `CLAUDE.md`/`AGENTS.md` instructions.
<!--
Title (for the Pull Request title field at the top):
Use a short prefix so the change type is obvious. You do not need to
repeat it in the body below.
Examples:
- fix: — bugfix
- feat: — feature
- refactor: — internal change without user-facing feature
- docs: — documentation only
- chore: — tooling, CI, deps, build housekeeping
- test: — tests only
-->
## Linked issue (required)
<!-- Fixes#123 / Closes#123 / Refs #123 -->
closes#5001
This PR replaces the contents of `docs/` with symlinks to
`docs-site/developers/`
A caveat of this is that the metadata appears at the top of the file
instead of the title.
<img width="885" height="275" alt="image"
src="https://github.com/user-attachments/assets/430f9a71-e5a5-4412-983a-e4cfd7dc4714"
/>
We could either:
- Use ninja to copy the files from docs-site/developers and convert it
from .mdx to .md (Might be a problem with the symlink approach if mdx is
added to the contributor file later)
- Leave placeholder "For contribution instructions see: (link to
mintlify site)"s in the folder, which would have to wait until the
domain of the site is set. (Probably the best solution).
---------
Co-authored-by: Abdo <abdo@abdnh.net>
## Linked issue
Refs #4838#4839#4840
## Summary / motivation
Adds a contributor-facing guide for the test coverage setup introduced
across the three coverage PRs, and updates CLAUDE.md to reflect that
`just` is now the single entry point for all build, test, lint, and
format commands.
## How to test
- Read `docs/testing-coverage.md` — verify it covers all three stacks,
thresholds, and the known gaps section.
- Run `just docs` and open `out/docs/html/index.html` to confirm
`testing-coverage` appears in the sidebar under Contributing.
- Read `CLAUDE.md` — verify `./ninja` / `./tools` references are gone
and `just test-rust`, `just test-py`, `just test-ts` are mentioned.
### Details
- `docs/testing-coverage.md`: documents tools, thresholds, per-stack
entry points, and known gaps for all three coverage stacks.
- `docs/index.md`: wired `testing-coverage` into the Sphinx toctree
after `contributing`.
- `CLAUDE.md`: replaced raw `./ninja` / `./tools` invocations with
`just` equivalents; added top-level note directing contributors to
`just --list`; added `just test-rust`, `just test-py`, `just test-ts`
to the Quick iteration section.
---------
Co-authored-by: Abdo <abdo@abdnh.net>