# Findings

A **finding** is one confirmed issue: a title, a severity, the file and line it lives at, and an explanation of how it fails. Findings from all runs in a project collect in the Findings view, where the open ones are your worklist.

Your own tools can file findings too. `POST /v1/findings` with a `findings:write` key records one from a scanner, an importer, or an agent of your own. It has no run behind it — the dashboard marks it **via API** where other findings link to their run — and otherwise behaves like any review finding: same triage, same deduplication, same fix flow.

## Severities

| Severity | Meaning |
|---|---|
| **High** | Exploitable or seriously damaging — fix before shipping. |
| **Medium** | Real weakness that needs a decision, if not an immediate fix. |
| **Low** | Worth fixing opportunistically. |
| **Info** | Worth knowing; no action demanded. |

## The lifecycle

Every finding starts **open**. Triage moves it to a closed state:

- **Issue resolved** — the issue was real and someone fixed it.
- **Ignored** — the issue is real, but you're accepting the risk or it doesn't apply.
- **False positive** — the agent got it wrong. This one needs a short note saying why. Those notes make good [knowledge](/docs/knowledge.md), so future reviews learn the pattern.
- **Duplicate** — another finding already tracks the same root cause in the same repository and file. Agents assign this during maintenance, and API clients can set it by naming the finding it duplicates. The dashboard shows the link but offers no button for it.

In the dashboard you can reopen a closed finding, then triage it again to move it elsewhere. API clients can go straight from one closed state to another.

You can also correct an open finding rather than close it: the [API](/docs/api.md) rewrites its title, body, file, or line, with a note explaining the change. The activity trail records which fields changed, the note, and — for a finding that moved — the file and line it came from. Earlier titles and bodies are not kept.

## Agent-driven maintenance

Agents triage through the same route people and API clients use. A maintenance run reads current code and git history, then marks findings resolved, duplicate, ignored, or false positive where it has evidence, and leaves the uncertain ones open. Every change an agent makes carries a note, whatever it decides.

**Continuous maintenance** is the built-in task for this, on every project. It runs at most once a day and only after your code or your findings have moved, so a project nobody has touched is not re-triaged and not billed. One evidence-driven pass replaces separate deduplication and merged-fix reconciliation jobs.

## Exporting

The **Export** menu on the Findings view takes whatever the filters currently select — every matching finding, including the ones past **Show more** — as **CSV**, **JSON**, or a **PDF** report.

- **CSV** is one flat row per finding, for a spreadsheet or an issue tracker.
- **JSON** carries the findings plus the counts, the filters you exported under, and whether the set was cut short.
- **PDF** opens on a cover naming the organisation and date, then a summary naming every filter with counts by severity and status and a contents list, then each finding in full. It is capped at 250 findings — the layout is expensive enough that a larger report would lock up the browser — and says so when it truncates. CSV and JSON go to 5,000.

All three are built from `GET /v1/findings`, which is also how you'd export from your own tooling: page it with `next_cursor` until you have the set you want (`total` tells you how many there are), and each row names its repository. Over MCP that's `ozone_list_findings`. Project names come from `GET /v1/projects` — findings carry `project_id`, not the name.

## Activity and discussion

Each finding has an activity view recording status changes and rewrites with their actor and evidence, and its header names the commits it came from. People and agents share its comment thread, so context and decisions stay attached to the issue.

You can triage straight from the PR comment too: **Mark resolved** and **Ignore** links there act on the finding once you confirm, and skip harmlessly if someone already triaged it. False positive stays in the dashboard, where the note belongs.
