Draft: Let a foundational flow declare the reference it bills as

What does this merge request do and why?

Adds a billing_reference attribute to foundational flow registry entries, so a flow can bill as a reference other than its own.

The problem. Credits are keyed on the flow reference: Ai::UsageQuotaService sends it to CustomersDot as feature_qualified_name. A flow that replaces another behind a feature flag therefore moves customer billing the moment routing flips.

Worse, it does so quietly. UsageQuotaService only treats 402 and 403 in the response as errors, so an unmapped reference falls through to success — the flow runs silently unbilled, and nothing in the UI says so.

The change. A billing_reference attribute, consumed only where CreateWorkflowService constructs UsageQuotaService. nil keeps today's behaviour, so no existing flow changes. Rate limits and analytics stay on the flow's own reference, which is where we want to see them.

First user is slack_assistant/v1 in !254799 (merged), which sets it to developer/v1 so a Slack mention bills exactly as it does today. This MR is independent of that one but must merge before routing reaches production.

Related to #628428 (closed)

How to set up and validate locally

The specs are the current safety net here.

For a manual check, temporarily log the value in CreateWorkflowService#billing_reference and start a flow whose registry entry sets the attribute. It should return the declared reference, not the flow's own. A bigger end to end test is then planned in the MRs further up the stack.

Open question for review

Is pointing a second flow reference at Duo Developer's CustomersDot key acceptable, or should a new reference get its own mapping? Asking whoever owns that mapping before this merges.


Stack — merge in this order:

  1. !254800 (closed)billing_reference attribute. Must reach production before routing, or credits key on an unmapped reference and the flow runs silently unbilled.
  2. !254799 (merged) — registry entry and feature flag. Sets billing_reference, so it needs the attribute from !254800 (closed).
  3. !254801 (merged) — routing. The only MR that changes behaviour.

Each is inert until the last one merges: the entry is unreachable without routing, and the attribute does nothing until a flow sets it.

Edited by Thomas Schmidt

Merge request reports

Loading
Loading