Lesson 9 of 9 · 20m
Making the Loop Work: Triage, Ownership, and Trust
The scanners are the easy half — the program survives or dies on one triage queue, clear ownership, expiring exceptions, and honest metrics.
None of the previous eight lessons is the hard part. Any engineer can add a scanner to CI in an afternoon. The hard part is day 30, when the tools have found 400 things, the same exhausted person is triaging all of them, and developers have quietly started vendoring dependencies so the lockfile audit goes quiet. The pipeline is a sociotechnical system — the scanners are the easy half.
One queue, or findings rot in five places
Semgrep has a dashboard, Trivy prints to CI logs, GitHub has code scanning, Dependabot files PRs. If each tool reports into its own silo, nothing is triaged — five dashboards is zero dashboards. Push everything into one view (SARIF into code scanning is the free version, a findings platform is the scaled version), dedupe by file + rule + line, and let one queue feed triage.
Ownership: the code owner fixes, the platform team enables
A finding belongs to the team that owns the code — route it by CODEOWNERS, not into a security team's inbox. The security/platform team owns three things: the scanner configuration, the exception register, and the rules. When that split is unclear, security becomes the fix-it department, burns out, and the program quietly dies.
SLAs and the exception register
- Critical: days. High: weeks. Everything else: backlog with a quarterly review.
- Every exception carries an owner and an expiry. An accepted risk that never expires is an unfixed bug wearing a suit.
- Baselines keep the queue honest: new findings gate, old findings are a tracked backlog with a burn-down.
Metrics that tell the truth
| Metric | What it tells you |
|---|---|
| Mean time to remediate, by severity | Is the loop actually closing? |
| % findings dismissed as false positives | Is the tooling noisy? Tune or replace it. |
Gate bypass / --no-verify count | Are people routing around you? |
| Findings per PR over time | Are developers learning or just complying? |
The metric to avoid is raw finding count — it rewards running noisier scanners and punishes fixing the backlog. I've watched a team celebrate 3,000 findings like an achievement; it was a debt ledger.
When developers route around you
--no-verify baked into commit scripts, vendored dependencies, continue-on-error quietly appearing in pipelines, PRs split into five pieces to dodge size limits. Each one is a signal that a control costs more than it returns. The right response is never "enforce harder" — it's "find out why this control is expensive and fix that." A gate developers route around protects nothing, and it teaches them the rest of your gates are ignorable too.
Field notes
- Review the exception register monthly; the entries nobody can explain get un-accepted.
- Rotate triage duty through the dev teams, not just security — nothing tunes a noisy rule like the people who suffer it owning the triage.
- The program is working when findings-per-PR trends down because the code got better — not because the scanner got quieter.