Platform

A finding with a history, not just a severity

The lifecycle is one state machine, implemented once. Its transition table is data, so an exhaustive test can enumerate every pair of states and assert the answer — including the transitions that must be refused, which is most of what a state machine is for.

The states

Five, and the moves between them

open
A scan observed it. Nobody has looked yet.
triaged
Someone has read it and accepted it into the backlog.
suppressed
Risk accepted, with a reason, an owner, and an expiry of at most two years.
resolved
A scan that would have found it did not. Only evidence closes a finding.
reopened
It was fixed and came back. Permanently distinguishable from never-fixed.
the transition table
open      → triaged, suppressed
triaged   → open, suppressed
reopened  → triaged, suppressed
suppressed→ open, triaged, suppressed (amend)
resolved  → reopened

Everything else is refused.

Three decisions

Rules that are opinions, not omissions

Each of these is a thing the product will not let you do, and the reason it will not.

A person cannot mark a finding resolved

“Resolved” means a scan that would have found it did not. That is a statement about evidence. A button that set it would let someone assert evidence they do not have, and the next scan would contradict them. Fix it and rescan, or suppress it with a reason.

A resolved finding cannot be suppressed

There is nothing to suppress — it is already closed. Pre-emptively accepting a risk that may return is a statement about a class of issue, which makes it a policy rule rather than a note on one row.

A reopened finding cannot be relabelled as open

“Reopened” records that something was fixed once and came back. That is the most interesting fact a vulnerability programme produces, and quietly downgrading it would erase a regression from the backlog while the timeline still says it happened.

Identity

Why the decision survives the rescan

A finding's identity is derived from its content — not from its position in a report, and not from anything that legitimately changes.

Severity, line numbers and the installed version are deliberately excluded from identity. A vulnerability that is re-rated is the same vulnerability; a package that moved is the same finding. If identity included those, every re-rating would orphan the triage you had already done and hand you a brand-new finding to decide about again.

Because identity is content-derived rather than engine-derived, it also survives a change of detection engine. That matters commercially: the decision record is TRUSTIVAN's, and it does not evaporate if what produces the raw findings is ever replaced.

Audit

Who did what, and what was merely automatic

Every transition writes to an append-only timeline that names the kind of actor responsible.

A change can be caused by a person, a scan, a scheduled system task, or an API key — and the record says which. No audit row ever claims a person did something a pipeline did.

The distinction extends to suppression. When an acceptance lapses, that is recorded as its own action, separate from someone actively changing their mind — because “the owner reconsidered” and “nobody renewed it” call for different conversations.

Audit coverage is complete for findings and verdicts, and extends to webhook, identity-provider, SCIM and membership changes. Asset changes are not yet recorded in the same way.