A finding is one stored row that says something specific is wrong or worth a look at a specific place: a marker that lowers a file's health score, a file nothing imports, a committed credential, a markdown link to a heading that no longer exists. Every finding is computed from the index with no model, and every one carries the evidence that produced it.
The finding families
| Family | Produced by | Keyed by | Carries a triage status |
|---|---|---|---|
| Health findings | Code health markers across defect risk, maintainability and performance, plus governance findings | biomarker_type, with a dimension and severity | Yes |
| Dead-code findings | Dead code | kind: unreachable_file, unused_export, unused_internal, zombie_package | Yes |
| Refactoring plans | Refactoring intelligence | plan id and a content-derived public_id | Yes |
| Security findings | Security signals | kind and a fixed severity | No, see below |
| Documentation drift | Documentation drift | kind: path, link, anchor, command, symbol | No |
Health and dead-code findings meet in one place: dead-code percentage folds into module health, and the dashboard's Code Health page lists both. Security and documentation-drift findings sit on their own tabs of the same page and do not deduct from a file's health score.
Which finding types a surface shows
A finding type can be real in the analyzer and still too noisy to put in front
of a reader. The finding-type registry records, per dead-code kind and per
health biomarker_type, one of three states:
| State | What surfaces do |
|---|---|
validated | Shown everywhere. A type the registry does not list is validated. |
provisional | Shown only when a caller names the type or opts into unverified types, and then labelled unverified. |
hidden | Left out of every default surface, even when named. |
The registry changes visibility only. The analyzers still run, the rows are
still stored and scored, and the raw CLI analysis still reports them. What
changes is what the reading surfaces show: the MCP tools
(get_health, get_dead_code,
and the health blocks inside get_context and
get_risk), the REST finding lists, the dashboard's
attention list, file pages and "Do next" actions, the PR change-health review,
the generated CLAUDE.md, and the prompts behind the documentation pages.
Today three types are hidden, each with the measurement that put it there:
| Type | Family | Why it is hidden |
|---|---|---|
unused_internal | Dead code | Measured at 0.5% precision on 1,511 hand-labelled findings. TS/JS/Python emit no same-file read edges, so a private symbol used only in its own file looks unused. |
duplicated_assertion_block | Health | Clones are matched on token shape only, so unrelated assertions pair up. |
dry_violation | Health | Flags duplicated import blocks and data literals as design duplication. |
No type is provisional today. A type returns to validated only when its
measured precision clears the bar for its family.
get_dead_code says what it held back instead of shrinking silently: when a
withheld type had rows, its summary carries a withheld_types entry with the
count, the state and the reason.
get_dead_code() # hidden kinds left out, counted in summary.withheld_types
get_health(include=["unverified"]) # also show provisional types, labelled "unverified"Triage: setting a status
Health findings, dead-code findings and refactoring plans share one status vocabulary:
| Status | Meaning |
|---|---|
open | Outstanding. The default, and what every list shows unless asked otherwise. |
acknowledged | Real, and the team is not acting on it now. |
resolved | Fixed, or the code moved on. |
false_positive | Wrong for this repository. |
Where you set it:
- Dashboard. The health drawer on the Code Health page and the dead-code list have a status control per finding.
- MCP.
set_finding_statussets the status of one refactoring plan. It is opt-in and the only tool on the MCP surface that writes. - REST.
PATCH /api/repos/{repo_id}/health/findings/{id}for a health finding andPATCH /api/dead-code/{id}for a dead-code finding, on the local server started byrepowise serve.
There is no CLI command for triage.
What persists across re-analysis
A re-run of the analysis replaces only open rows, so a status you set is
never overwritten. What the next run does with the same issue depends on the
family:
- Dead code. A finding you acted on is not re-created. The next run drops any new finding that matches it on file, kind and symbol.
- Refactoring plans. A plan marked
false_positiveis never re-emitted. A plan a person markedresolvedstays resolved even if the detector still fires.acknowledgedrecords the judgment without suppressing anything. - Health findings. The triaged row and its status survive, but the next
run does not match against it. If the marker still fires, the same issue can
be listed again as a new
openfinding.
Security and documentation-drift findings
Neither family has a status in the local index. To silence a security finding
in the CI gate, put a repowise-security-ignore comment on its
line (repowise-security-ignore: kind, kind for specific kinds).
repowise security check then counts it as suppressed and does not fail on it.
A documentation-drift finding goes away when the document or the tree is
fixed, since the check runs again on every update.
On the hosted platform, the Security page's secret and vulnerability lists carry statuses of their own, and only the repo owner can change them.