Report results per ecosystem because a single total can hide a tool that is strong in Node and weak in Go. Show the counts behind each figure, then weight ecosystems by how much of your estate they represent, so the headline reflects your reality.
How averages mislead
Say you run mostly JavaScript, with a few Python services and one Go tool. Scanner A is excellent in JavaScript and poor in Go. Scanner B is average everywhere. Pooled across all repositories, A may look better, which is right for you. Pooled across repositories where Go happens to be a large share of the sample, B may win, which is wrong for you.
The pooled number depends on your sample mix. The per ecosystem numbers do not.
The table to produce
For each scanner and each ecosystem, record the same few measures.
| Ecosystem | Packages in reference | Identified by scanner | One sided true positives | False positives |
|---|---|---|---|---|
| Node | count | count | count | count |
| Python | count | count | count | count |
| Go | count | count | count | count |
Keep raw counts visible. "412 of 430" is more honest than "96 percent," because small denominators produce shaky percentages. With a handful of Go packages, one miss moves the figure a lot.
Pick the right measures per ecosystem
Not every measure carries the same weight everywhere.
- Inventory match. Compare against the lockfile, as in comparing package inventories first.
- Precision. Share of reported findings that adjudication confirms. See how to calculate it.
- One sided true positives. Real issues that only this tool reported.
- Unsupported. Mark clearly when a tool did not process an ecosystem at all. Zero findings in an unsupported ecosystem is not a clean result. It is a gap, as covered in what ecosystem support actually means.
Weight by your estate
Next, translate the per ecosystem table into one decision, but do it deliberately. Count how many of your production repositories, or how many engineers, work in each ecosystem. Assign weights from that, and write them down before the first scan, as described in the decision rule post.
| Ecosystem | Share of estate | Weight |
|---|---|---|
| Node | Large | High |
| Python | Medium | Medium |
| Go | Small | Low, but a hard requirement if critical |
A small ecosystem can still be a must have. If your payments service is the only Go code and it matters most, make that a pass or fail line, not a weight.
Show the weak cell
In the readout, show the worst result for each tool, not only the average. Decision makers often change their mind when they see that a tool failed on the one service they care about. Include which repositories drove each cell, so readers can look at specifics.
Mind the small numbers
Where an ecosystem has only one or two repositories, say so. Avoid ranking tools on tiny samples. Instead write "tool B did not identify four of nine packages in the one Go repository," and let readers apply judgment.
Keep it consistent across reports
Use the same table for every repository group and every rerun, so changes over time are visible. A rerun after a few weeks will show whether per ecosystem results are stable.
Safeguard's dependency scanning reports across ecosystems, and the free scan at gold.safeguard.sh/scan lets you see per repository results to feed your own table.
Quick check
Can I still give leadership one number?
Yes, if the weights were set in advance. Show the per ecosystem table beside it so the number can be checked.
What about ecosystems we plan to adopt?
List them separately as future needs, and test one small repository so a gap is known early.
Last reviewed: 19 October 2026.