feat: v0.2.0 -- breaking schema bump, new derived fields, vulnerability throughput collection

Summary

v0.2.0 ships a breaking collection.json schema change plus new derived aggregate fields and a new vulnerability-throughput collection stage. schema_version stamps bump 1.0.0 -> 2.0.0; readers must handle the new shape. The wire breakage is intentional and surfaced by the semver major bump.

Breaking

  • schema_version = "2.0.0".
  • mr_authors changes from an array ([{count: N}, ...]) to a compact summary object:
    {
      "active_authors": 312,
      "total_mrs": 8946,
      "top_share": { "top_5": 0.18, "top_25": 0.52, "top_50": 0.74 },
      "percentiles": { "p50": 8, "p75": 19, "p90": 45, "p95": 87, "p99": 201, "max": 428 }
    }
    Size is flat and constant regardless of instance size, no identifiers.
  • avg_critical_vulns_per_month retired from the export. It was identical by construction to the new avg_vulns_detected_per_month; v2.0.0 is the right window to drop the redundant name.
  • health-report.json zone fields (mr_velocity_zone, pipeline_zone, security_zone) can now emit UNKNOWN in addition to GREEN / YELLOW / RED. Exhaustive switches must handle the new variant.

Added

  • Vulnerability throughput collection. Per-month vulns_detected, vulns_resolved, and vuln_mttr_days gathered from the GitLab GraphQL vulnerabilities connection with detection + resolution timestamps. Exported as the aggregates avg_vulns_detected_per_month, avg_vulns_resolved_per_month, and a resolution-weighted vuln_mttr_days. Complements the existing snapshot count (critical_vulns) with actual throughput + time-to-resolve.
  • Per-month failure_rate on each monthly[] entry plus aggregate avg_pipeline_failure_rate and pipeline_failure_rate_trend_pct (same first-3 vs last-3 comparison used by mr_trend_pct).
  • mrs_per_active_user_per_month aggregate field, derived from total MRs, active authors, and the collection window.

Changed

  • CI container_scanning now declares its container-build need as optional: true so template-versus-catalog rule mismatches no longer emit a "missing-needs" warning.
  • failure_rate clamped to [0.0, 1.0] defensively.
  • mrs_per_active_user_per_month numerator and denominator now share the same full-window population to avoid a subtle skew when activity is concentrated in the partial month.
  • Documented the MTTR early-exit pagination bias in SECURITY.md (a vulnerability detected before the window but resolved inside it may be missed; the effect biases MTTR downward).
  • README notes that mr_authors.percentiles values are most meaningful for ~10+ active authors; on very small teams percentiles collapse toward max by nearest-rank definition.

Test plan

  • go vet ./... clean
  • go build ./... clean
  • go test -count=1 ./... clean (full suite ~3s)
  • Synthetic export round-trip: schema_version emits "2.0.0"; all new fields serialize; no NaN / missing keys on zero-value inputs
  • PII regression guard (TestToExport_NoPII) still green under the new mr_authors shape
  • Partial-run semantics from v0.1.1 preserved (PARTIAL banner, UNKNOWN zones, (unknown) count annotations)
  • Percentile math verified by hand at N=0,1,2,10,100
  • Resolution-weighted MTTR math verified against synthetic 12-month vuln-throughput fixture
  • gofmt clean across the tree (includes normalising pre-existing drift in report/config files)
  • Four independent audits (simplify, adversarial context-leak, UX + schema-compat, vale) -- zero blockers at final sweep
  • CI pipeline green
  • Release pipeline produces clean artifacts on tag
Edited by Andrew Dunn

Merge request reports

Loading