Task · GCI-0016

Unscore components that cannot be evaluated, before improving any matcher

Description

The coverage score divides by 7 unconditionally. Measured across a 270-stack estate, three of those seven components are structurally unsatisfiable on almost every stack, so the score reports absent product adoption as failed coverage. THIS is the dominant defect, not the dashboard matcher.

Measured effect, and why matcher work must come second

change estate mean completeness
current (dashboard always no, denominator always 7) 17.7%
+ a fully working dashboard matcher, denominator still 7 18.1% (+0.4pp)
+ unscored scheme, matcher unchanged 26.4% (+8.7pp)
+ machine-generated identities row-unscored 27.3%

A perfect matcher is worth less than a twentieth of what honest unscoring is worth. Do the unscoring first.

The three structural zeros

Scoring these as no is the same defect as the dashboard tag, three times over, and it is exactly what the sibling maturity pillar already refuses to do with its explicit unscored reasons.

Unscoring rules

Component Unscored when Reason enum
profiles Pyroscope read SUCCEEDED and returned zero services signal_not_in_use
slo stack owns zero SLOs product_not_in_use
alert alert inventory available and rules_total == 0 product_not_in_use
alert alert inventory unavailable inventory_unavailable
dashboard dashboard inventory unavailable inventory_unavailable
dashboard query-detail fetch failed for the stack evidence_unavailable
metrics / logs / traces NEVER -

Metrics, logs and traces are the observation itself. A service present in one signal and absent from another is a real finding and must keep scoring no.

dashboard is NOT unscorable merely for a stack having no dashboards: zero of 270 stacks have no tenant-authored dashboards. Where a stack has dashboards and the service has none, no is honest.

Row-level unscoring: one class only

A register row whose identity is machine-generated gets unscored_reason = ephemeral_identity, is excluded from aggregates, and STAYS VISIBLE in the view. Detected from the name alone, no config, no maintained list:

\.(scope|service|slice|socket|mount|timer|target|device)$
^session-\d+
^user-\d+
\d{8,}
[0-9a-f]{8}-[0-9a-f]{4}-

Measured: 425 of 3,566 published rows (11.9%), and 12,459 of 18,376 in the full canonical set (67.8%). The \d{8,} rule is a heuristic and will catch a legitimately numbered service, so publish the count as its own metric and keep the rows visible with the reason attached rather than dropping them.

Denominator and disclosure

Acceptance Criteria

Definition of Done

Implementation Plan

  1. Add decision tests for per-component applicability, the four-component score floor, and ephemeral row visibility/exclusion.
  2. Make the score calculator version 2 and compute weighted scores only across applicable components while retaining numerator/maximum evidence.
  3. Derive profile, SLO, alert, dashboard, and row-level unscored reasons from the existing left-joined inputs; emit bounded unscored and mean score/denominator metrics and expose reasons in the service/summary views.
  4. Rebuild the Coverage dashboard around a paired mean-completeness/mean-denominator disclosure and render the unscored reason counts.
  5. Regenerate BUDGET.md, run targeted tests, the full item gate, CodeRabbit, review the diff, then finalize, commit to main, and push.

Implementation Notes

VERIFIED against independent sources after the product owner challenged the profiles and SLO figures. Both hold, and both mean the products are barely used - which is the point of unscoring them rather than scoring them as failures.

Profiles, three independent measurements agreeing:

So 269 of 270 measured stacks have zero profiling data while every stack has the instance provisioned. That gap is itself a finding of the same shape the estate pillar already publishes for other provisioned-but-unused capabilities, and it belongs on the surface alongside the unscored reason.

SLOs, two independent measurements agreeing:

So 266 of 270 stacks own no SLO. grafanacloud_slo_* does not exist as a metric family; do not look for it.

For scale, over the same 24h window: 269 stacks ingest logs and 232 ingest traces. Profiles at 1 and SLOs at 4 are the outliers by three orders of magnitude, not a measurement artefact.

Wording rule for whoever implements this: state these as “N stacks have NO profiles” or “M stacks own zero SLOs”. A bare “269/270” next to the word profiles reads as the opposite of what it means and was misread once already.

Implemented score version 2 with explicit applicability, a four-component percentage floor, bounded component/reason counts, paired mean score and denominator metrics, and visible-but-aggregate-excluded ephemeral identities. Targeted coverage, dashboard, budget, guard, compose, and hydration checks pass; the dependency derivation remained unchanged.

Final verification: 1398 passed, 2 skipped, 6614 subtests; OpenTofu formatting and both module validations passed; customer-identifier working tree and history scans passed; shipped-text check passed; CodeRabbit re-review completed with zero findings.

Final Summary

Made coverage score version 2 defensible by scoring only applicable components, withholding thin percentages, excluding visible ephemeral identities from aggregates, and publishing bounded unscored reasons with a population-matched mean denominator. Verified through the full offline suite, dashboard/view coverage gates, generated budget, Terraform validation, privacy/text gates, and a zero-finding CodeRabbit re-review.

View the source file on GitHub