Triage
Findings live at the project level with branch attribution — not per-campaign. That means triage decisions carry across branches and across merges/renames, and "show only NEW issues on this PR" is first-class.
Set a status
Every human action records actor attribution (actor_user_id, nullable for system/client actions). Statuses you can set on a finding:
- Open — default for a newly discovered finding.
- Fixed — you believe it's resolved (a retest campaign can verify).
- Won't fix — accepted risk; stays suppressed on derivative branches.
- False positive — recorded with a reason; feeds back into dedupe tuning.
See what's new on a PR
The PR gate reports open findings whose earliest sighting is on the PR branch and, for incremental campaigns, at least one finding file intersects changed_paths. Two residual false-positive sources, with mitigations:
- Renames are absorbed by the alias/dedupe layer — a renamed file re-imports as KNOWN, not new.
- Model nondeterminism (a pre-existing issue the model simply never emitted on
main) is mitigated by keeping a reasonably fresh full scan of the default branch and reporting "new vs merge-base baseline" alongside "new to project".
Merge duplicates
Findings are soft-merged — losers are repointed to the keeper via merged_into_finding_id and alias rows are repointed too. A merged-away fingerprint re-imported later lands on the keeper deterministically. Triage state on the keeper wins.
Trust the dedupe layers
Dedupe runs in tiers:
- Exact fingerprint fast path (deterministic sha256).
- Heuristic candidate search — file/category overlap + trigram title match, ranked in app code with a deterministic scorer + stable tiebreak. Bounded candidates per finding.
- AI adjudication (paid lever) — fires only when a pair shares a file or category and heuristic confidence ≥ threshold and the pair isn't cached. An incoming finding's eligible candidate pairs are adjudicated in batched requests of up to
AI_DEDUPE_BATCH_SIZEpairs, with strict per-entry validation, individual retry for missing or malformed entries, and truncation at the daily pair cap. The merge policy treats a substantial subset/superset pair as the same finding, even when the broader report adds secondary defects or evidence. Deterministic fallback on any failure. On-prem uses your key; a platform key never ships in the image.
Heuristics-only is the free tier.
Export safely
Model-derived text is treated as untrusted input. The web UI renders it as text only (no HTML interpolation) and exports escape it, so a prompt-injection payload in a finding title renders inert. See Data handling.
Next steps
- PR gate — surface triage into CI.
- Data handling — retention, isolation, right to delete.