Skip to content

feat(signer): BYOC per-capability pricing + real capability/model usage labels#3972

Open
seanhanca wants to merge 4 commits into
feat/add-model-id-signer-kafkafrom
feat/byoc-per-cap-pricing-and-usage-labels
Open

feat(signer): BYOC per-capability pricing + real capability/model usage labels#3972
seanhanca wants to merge 4 commits into
feat/add-model-id-signer-kafkafrom
feat/byoc-per-cap-pricing-and-usage-labels

Conversation

@seanhanca

Copy link
Copy Markdown

Summary

Combines #3966 (usage-attribution labels) and #3967 (per-capability pricing) into a single PR. Both change-sets live entirely on the remote signer (server/remote_signer.go GenerateLivePayment and its cmd/livepeer/starter flag plumbing); no orchestrator code is touched. This PR supersedes and replaces #3966 and #3967, which are being closed in favor of this one.

The two features are complementary and are both included in full:

  • Usage attribution (from fix(signer): meter real BYOC capability + model_id for usage events #3966): additive Capability / ModelID fields on RemotePaymentRequest override the metered pipeline/model_id labels on the create_signed_ticket usage event, decoupling usage attribution from Type (which still drives fee/pixel routing). Includes the addressed review fixes: sanitizeUsageLabel (TrimSpace + 128-rune cap via maxUsageLabelLen) to bound Kafka payload size / label cardinality, corrected docstring, and hardened TestResolveUsageLabels (per-subtest require, whitespace-only + oversized cases).
  • Per-capability pricing (from feat(signer): charge BYOC live payments at the per-capability price #3967): resolveByocPrice resolves the BYOC fee from the orchestrator's advertised OrchestratorInfo.CapabilitiesPrices (keyed on req.Capability), gated behind the new default-OFF -byocPerCapPricing flag (LivepeerNode.ByocPerCapPricing). Includes the addressed review fixes: additional Type==lv2v gate on the pricing branch, and skip-invalid-duplicate-and-keep-scanning in the price resolver. The resolved price is written back to oInfo.PriceInfo so state init / initialPrice / max-price ceiling / ExpectedPrice / the validatePrice doubling guard stay cap-vs-cap consistent.

When the flag is OFF (default), req.Capability is empty, Type != lv2v, or no usable cap price matches, behavior is byte-identical to the base-price path — zero regression.

Provenance / review fixes carried over

Cherry-picked #3966 head f7d2f83 on top of #3967 head 84c706a; the two edit resolveUsageLabels/TestResolveUsageLabels complementarily and merged cleanly (no manual conflict). All previously-addressed Copilot review feedback on both #3966 and #3967 is preserved. Commits retain original authorship (incl. the Co-authored-by: Cursor trailer on the pricing feat commit).

Test plan

  • resolveUsageLabels / sanitizeUsageLabel / maxUsageLabelLen present and used (labels union).
  • resolveByocPrice / -byocPerCapPricing / Type==lv2v gate / invalid-duplicate skip present (pricing union).
  • gofmt-clean, no conflict markers, imports (math, strings) present.
  • CI: hermetic CGO-free tests TestResolveUsageLabels, TestResolveByocPrice, TestGenerateLivePayment_ByocPerCapPricing (local run blocked only by host ffmpeg/lpms CGO mismatch; validated via CI).

Made with Cursor

seanhanca and others added 4 commits June 26, 2026 20:21
The remote signer hardcoded the create_signed_ticket `pipeline` to the
lv2v constant whenever the gateway sent `type:"lv2v"` (which BYOC jobs
always do for fee/pixel routing), and derived `model_id` only from the
LiveVideoToVideo capability constraints. For BYOC capabilities (e.g.
nano-banana) this emitted pipeline=live-video-to-video and an empty
model_id, which the OpenMeter collector recorded as
live-video-to-video / unknown.

Add two additive, backward-compatible fields to RemotePaymentRequest:
`capability` and `model_id`. When set by the gateway, they override the
metered pipeline + model_id labels, decoupling usage attribution from
`Type` (which still drives fee/pixel routing). When empty, behavior is
byte-identical to before (lv2v constant + capabilities-derived model id;
collector defaults empties to "unknown").

Label resolution is extracted into a pure resolveUsageLabels helper with
a hermetic table test (TestResolveUsageLabels) that runs without the CGO
ffmpeg toolchain.
The remote signer's GenerateLivePayment charged every BYOC generation a
flat, model-independent fee: it read only oInfo.PriceInfo (the base price)
and synthesized lv2v pixels (1280*720*30 * billableSecs), so nano-banana,
recraft-v4, ltx-*, etc. all cost the same regardless of the per-capability
prices the orchestrator already advertises in oInfo.CapabilitiesPrices.

Resolve the fee per capability instead, keyed on req.Capability (added for
metering by the stacked #3966): scan oInfo.CapabilitiesPrices for the
Capability_BYOC entry whose Constraint matches the capability and charge
that USD->wei/sec rate over compute-seconds (pixels = ceil(billableSecs)).
This aligns the gateway's paid amount with the orchestrator's existing
per-capability per-second accounting (byoc.JobPriceInfo * seconds).

The resolved price is written back to oInfo.PriceInfo so it is the single
source for state init, initialPrice, the max-price ceiling, the payment's
ExpectedPrice (which the orch uses to set its fixed per-session price), and
the price-doubling guard in validatePrice (which reads
sess.OrchestratorInfo.PriceInfo) -- keeping all of them cap-vs-cap
consistent and preventing a false "price more than doubled" rejection when
base and cap diverge.

Gated behind a new default-OFF flag (-byocPerCapPricing /
LivepeerNode.ByocPerCapPricing). When OFF, or when req.Capability is empty,
or when no usable cap price matches, behavior is byte-identical to the
base-price path (zero regression). resolveByocPrice is a pure, hermetically
testable function; ticket params (faceValue/winProb) are passed through
unchanged so EV/ticket math stays valid.

Tests: TestResolveByocPrice (resolution, fallback, non-BYOC/zero-rate
ignored) and TestGenerateLivePayment_ByocPerCapPricing (flag-off
zero-regression, per-cap seconds fee, 2:1 tariff ratio, unknown-cap
fallback, doubling-guard not tripped), both CGO-free.

Co-authored-by: Cursor <cursoragent@cursor.com>
Addresses Copilot review feedback on PR #3967:

- resolveByocPrice now skips a matched-but-invalid (non-positive rate) entry
  and continues scanning instead of returning nil, so a later valid duplicate
  entry for the same constraint (e.g. from a misconfiguration) is still
  honored. Added a regression test case. (Copilot, remote_signer.go:431)

- BYOC per-capability pricing is now additionally gated on
  Type==RemoteType_LiveVideoToVideo. Enabling it changes the billing basis
  (overrides req.InPixels and bypasses lv2v pixel synthesis), so it must only
  apply to the lv2v job type that BYOC jobs always use, never to a non-lv2v
  request that happens to carry a capability. (Copilot, remote_signer.go:488)
Addresses Copilot review feedback on PR #3966:

- resolveUsageLabels now sanitizes the gateway-supplied capability/model_id
  override labels (TrimSpace + cap at 128 runes via sanitizeUsageLabel) before
  they are emitted to the create_signed_ticket usage event, bounding Kafka
  payload size and downstream label cardinality. req.Capability/req.ModelID
  come from the request body, so an unbounded value could otherwise inflate
  cardinality (pipeline was previously a small fixed set).

- Corrected the resolveUsageLabels docstring: the capability/model_id overrides
  apply regardless of Type, not only for lv2v; clarified the empty-field
  fallback wording.

- TestResolveUsageLabels now constructs a fresh require.New(t) inside each
  subtest so failures are attributed to the correct subtest, and adds cases for
  whitespace-only (ignored) and oversized (length-capped) override labels.
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b1326d49-384f-45da-88a1-1ca3a18b1f21

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/byoc-per-cap-pricing-and-usage-labels

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

go Pull requests that update Go code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant