Add nonBillableUsage to GitlabSubscriptionUsage

What does this MR do and why?

Adds nonBillableUsage to GitlabSubscriptionUsage, so the GitLab Credits dashboards (group dashboard on GitLab.com, instance dashboard on self-managed) can show usage that was not billed, per product and skip reason.

It proxies CustomersDot's new gitlabCreditsUsage.nonBillableUsage field:

  • Client: SubscriptionUsageClient#get_non_billable_usage sends its own query (GET_NON_BILLABLE_USAGE_QUERY), so a failure here does not fail creditsUsed / dailyUsage. It respects flowTypes, like get_subscription_usage.
  • Failure handling: when its ClickHouse read fails, CustomersDot returns nonBillableUsage: null with the error nonBillableUsage is temporarily unavailable. The client logs a warning and returns success: false, without raising or reporting to Sentry, so the field resolves to null and the rest of subscriptionUsage still resolves. Any other error raises as before.
  • Model: GitlabSubscriptions::SubscriptionUsage#non_billable_usage maps the response to NonBillableUsage Structs, reusing DailyUsage.
  • GraphQL: new GitlabSubscriptionUsageNonBillableUsage type with:
    • productId: matches GitlabSubscriptionUsageProduct.id.
    • skipReason: nullable; null means the event has no recorded reason.
    • totalCreditsUsed
    • dailyUsage

These totals are not included in creditsUsed or dailyUsage, so billed totals still reconcile with Customers Portal.

The frontend (stacked chart in wallet_agnostic_credits_dashboard) follows in a separate MR, for multi-version compatibility.

References

Screenshots or screen recordings

Screenshot 2026-10-06 at 8.41.47 PM.png

Screenshot 2026-10-06 at 8.44.45 PM.png

How to set up and validate locally

  1. Run GDK in SaaS mode (export GITLAB_SIMULATE_SAAS=1 gdk restart).

  2. Run CustomersDot locally on the branch from https://gitlab.com/gitlab-org/customers-gitlab-com/-/merge_requests/17365, connected to your GDK.

  3. Have a group with GitLab Credits and generate usage, including some events with SkipConsumption = true in usage_billing_enriched (with and without a skip_reason key in Metadata).

  4. As a group owner, run this in https://gdk.test:3443/-/graphql-explorer:

    query {
      subscriptionUsage(namespacePath: "test-group-hvs-101", startDate: "2026-10-01", endDate: "2026-10-06") {
        creditsUsed
        nonBillableUsage {
          productId
          skipReason
          totalCreditsUsed
          dailyUsage {
            date
            creditsUsed
          }
        }
      }
    }
  5. Check that nonBillableUsage lists one entry per product and skip reason, skipReason is null for events without a reason, and creditsUsed is unchanged.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Harsh Vardhan Sharma

Merge request reports

Loading
Loading