Skip to content

fix(byoc): type:byoc payments + capabilities on orch discovery#41

Closed
seanhanca wants to merge 3 commits into
mainfrom
fix/byoc-e2e-inference-type-byoc
Closed

fix(byoc): type:byoc payments + capabilities on orch discovery#41
seanhanca wants to merge 3 commits into
mainfrom
fix/byoc-e2e-inference-type-byoc

Conversation

@seanhanca

@seanhanca seanhanca commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • submit_byoc_job / _create_byoc_payment: Send type:"byoc" with BYOC capabilities protobuf on /generate-live-payment (no legacy capability string field). Matches John’s c6d312f intent on the inference path.
  • get_orch_info: Pass the same BYOC capabilities protobuf during orch discovery so advertised CapabilitiesPrices match the job constraint.
  • capabilities.py: Add CapabilityId.BYOC + byoc_capabilities_from_app() helper (required on main).

Depends on

  • go-livepeer PR (signer + orch): must accept type:byoc and verify V1 job creds before this path works end-to-end.

Test plan

  • python -m pytest tests/test_capabilities.py (add if missing — manual import check OK)
  • Local submit_byoc_job(...) with composite bearer → payment 200 → orch 200
  • OpenMeter: byoc/flux-schnell not unknown
  • lv2v / Scope paths unchanged (this PR only touches BYOC inference payment)

Note for John

Live-runner (type:"byoc" in LivePaymentSession) remains on ja/live-runner / bd8e780 lineage — this PR covers one-shot inference only. Stack live-runner change separately when deploying SDK canary.

Made with Cursor

Summary by CodeRabbit

  • New Features
    • Added BYOC capability identification and protobuf generation from the provided app value.
    • BYOC payment requests now embed the encoded BYOC capability data in signer payloads.
    • Legacy Daydream signers and newer signers use the appropriate payload format automatically.
    • Empty or whitespace-only app values are handled safely.
  • Documentation
    • Updated payment refresh documentation to clarify how the capability is embedded in BYOC capabilities sent to the signer.
  • Tests
    • Added unit tests covering BYOC capability encoding and correct inclusion/exclusion on signer payment requests.

Use BYOC capability constraints for get_orch_info and /generate-live-payment
so the signer can resolve per-cap pricing and usage labels without a legacy
capability string field.

Co-authored-by: Cursor <cursoragent@cursor.com>
@seanhanca
seanhanca requested a review from j0sh as a code owner July 10, 2026 23:42
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

BYOC payment generation now derives capability protobufs from the requested app, passes them to orchestrator discovery, and selects legacy or BYOC signer payload fields by signer host. Tests cover capability construction, routing, discovery threading, and payload encoding.

Changes

BYOC payment signing

Layer / File(s) Summary
BYOC capability contract
src/livepeer_gateway/capabilities.py, tests/test_capabilities.py
Adds capability ID 37, maps it to "byoc", builds optional BYOC capability protobuf messages from trimmed app values, and tests populated and empty inputs.
BYOC payment flow
src/livepeer_gateway/byoc.py, tests/test_byoc_payment.py
Selects lv2v for legacy Daydream signers and byoc otherwise, passes derived capabilities to get_orch_info, constructs conditional signer payloads, updates payment documentation, and verifies both flows.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PaymentFlow
  participant OrchestratorInfo
  participant Signer
  PaymentFlow->>PaymentFlow: Select payment type from signer host
  alt BYOC signer
    PaymentFlow->>OrchestratorInfo: get_orch_info(capabilities)
    OrchestratorInfo-->>PaymentFlow: ticket_params
    PaymentFlow->>Signer: generate-live-payment(type byoc, encoded capabilities)
  else Legacy Daydream signer
    PaymentFlow->>OrchestratorInfo: get_orch_info(capabilities=None)
    OrchestratorInfo-->>PaymentFlow: ticket_params
    PaymentFlow->>Signer: generate-live-payment(type lv2v, capability)
  end
  Signer-->>PaymentFlow: payment response
Loading

Suggested reviewers: j0sh

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: BYOC payment flow and orchestrator-discovery capability handling.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/byoc-e2e-inference-type-byoc

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/livepeer_gateway/byoc.py`:
- Around line 193-204: Build `byoc_caps` before the orchestrator discovery call
and pass that same protobuf as the `capabilities=` argument to `get_orch_info`;
retain it for constructing `payment_payload` so discovery and signing use
identical BYOC capability constraints.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 74aa7270-c9b2-4860-94ff-2cce17d75c50

📥 Commits

Reviewing files that changed from the base of the PR and between cc31b56 and 4e5870e.

📒 Files selected for processing (2)
  • src/livepeer_gateway/byoc.py
  • src/livepeer_gateway/capabilities.py

Comment thread src/livepeer_gateway/byoc.py Outdated
TicketParams must use PriceInfoForCaps when ByocPerCapPricing is enabled.
_create_byoc_payment now threads the same BYOC capabilities protobuf into
orch discovery and the signer payment payload.

Co-authored-by: Cursor <cursoragent@cursor.com>
@seanhanca

Copy link
Copy Markdown
Contributor Author

Addendum — per-cap TicketParams alignment (Run 33)

Prerequisite check for enabling -byocPerCapPricing: _create_byoc_payment was sending capabilities on /generate-live-payment but not on get_orch_info(). That left orch issuing TicketParams at base PriceInfo while the signer expects per-cap price when the flag is ON (Run 25 priceMatch=False class).

Fix (commit 1114138):

  • Pass capabilities=byoc_capabilities_from_app(capability) into get_orch_info() (reuse same proto for signer payload)
  • Added tests/test_capabilities.py (2) + tests/test_byoc_payment.py (2)

Tests: pytest tests/test_capabilities.py tests/test_byoc_payment.py tests/test_byoc_refresh.py tests/test_byoc_training.py13/13 PASS

Deploy: not run this session — merge + image rebuild pending j0sh approval per repo rules.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/test_byoc_payment.py (1)

93-116: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider next() instead of single-element list slice.

Ruff RUF015 flags line 108: [r for r in reqs if ...][0] is less idiomatic than next(...). In test code this is cosmetic, but next() also gives a clearer error if no match is found.

♻️ Optional refactor
-    signer_req = [r for r in reqs if "generate-live-payment" in r.full_url][0]
+    signer_req = next(r for r in reqs if "generate-live-payment" in r.full_url)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_byoc_payment.py` around lines 93 - 116, Replace the single-element
list selection in
test_create_byoc_payment_includes_capabilities_on_signer_payload with next()
over a generator expression filtering reqs for "generate-live-payment",
preserving the existing signer_req behavior while satisfying Ruff RUF015.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/test_byoc_payment.py`:
- Around line 93-116: Replace the single-element list selection in
test_create_byoc_payment_includes_capabilities_on_signer_payload with next()
over a generator expression filtering reqs for "generate-live-payment",
preserving the existing signer_req behavior while satisfying Ruff RUF015.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: caf2c653-7b37-4ced-acec-88168fbaa4dd

📥 Commits

Reviewing files that changed from the base of the PR and between 4e5870e and 1114138.

📒 Files selected for processing (3)
  • src/livepeer_gateway/byoc.py
  • tests/test_byoc_payment.py
  • tests/test_capabilities.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/livepeer_gateway/byoc.py

Gate type:byoc vs type:lv2v on signer host so sdk.daydream.monster can
serve Daydream keys (signer.daydream.live) and NaaP keys (pymthouse DMZ)
from one image without breaking legacy ticket signing.

Co-authored-by: Cursor <cursoragent@cursor.com>
@seanhanca

Copy link
Copy Markdown
Contributor Author

Run 35 follow-up: dual-path payment type (1bf13cd)

Run 35 audit confirmed PR #41 (commit 4e5870e / 1114138) sent type:byoc unconditionally, which breaks Daydream keys on the shared sdk.daydream.monster node — those still route to legacy signer.daydream.live (expects type:lv2v + string capability). SIGNER_FROM_VALIDATE=1 is innocent; it only switches signer URL for naap_ keys.

Fix

Added _payment_type_for_signer(signer_url) in byoc.py:

Signer host Payment shape Orch discovery
signer.daydream.live type:lv2v + capability string no capabilities proto (bd8e780 behavior)
pymthouse DMZ / other (e.g. pymthouse-production.up.railway.app) type:byoc + capabilities proto capabilities on get_orch_info (1114138 behavior)

This lets one SDK image serve both Daydream (pmth_/sk_) and NaaP (naap_) callers on sdk-staging-1.

Tests

tests/test_byoc_payment.py — 6/6 passed:

  • legacy Daydream signer → lv2v payload, no capabilities on orch discovery
  • pymthouse DMZ signer → byoc payload + capabilities threading

Deploy note

Rebuild SDK image from 1bf13cd and redeploy sdk-staging-1 to replace the broken byoc-type-byoc-4e5870e-2026-07-10 image. Rollback to byoc-lv2v-bd8e7807 is no longer required once the new image is live.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/test_byoc_payment.py (1)

152-152: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer next(...) over single element list indexing.

Building an entire list comprehension only to extract the first element can be replaced with the more idiomatic and lazily-evaluated next(...) function.

  • tests/test_byoc_payment.py#L152-L152: replace [r for r in reqs if "generate-live-payment" in r.full_url][0] with next(r for r in reqs if "generate-live-payment" in r.full_url).
  • tests/test_byoc_payment.py#L182-L182: replace [r for r in reqs if "generate-live-payment" in r.full_url][0] with next(r for r in reqs if "generate-live-payment" in r.full_url).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_byoc_payment.py` at line 152, Replace the list-comprehension
indexing used to assign signer_req with lazy next(...) generator expressions at
tests/test_byoc_payment.py lines 152-152 and 182-182, preserving the existing
generate-live-payment URL filter and first-match behavior.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/test_byoc_payment.py`:
- Line 152: Replace the list-comprehension indexing used to assign signer_req
with lazy next(...) generator expressions at tests/test_byoc_payment.py lines
152-152 and 182-182, preserving the existing generate-live-payment URL filter
and first-match behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: af6ef908-8e0d-4b3e-b4cd-0a220be0ee9e

📥 Commits

Reviewing files that changed from the base of the PR and between 1114138 and 1bf13cd.

📒 Files selected for processing (2)
  • src/livepeer_gateway/byoc.py
  • tests/test_byoc_payment.py

seanhanca added a commit that referenced this pull request Jul 18, 2026
…ge into ja/live-runner (#46)

## Why
The production SDK (`sdk-service:byoc-dual-path-1bf13cd`) carries a
**load-bearing byoc-payment fix that exists in no branch** — only in the
running container. That's an operational liability and it blocks a
unified gateway. This ports it onto `ja/live-runner` (the Live Runner +
Scope branch, PR #20 → main) so the consolidated gateway keeps BYOC
payment working while gaining LR.

## What
- `_payment_type_for_signer(signer_url)` — **legacy Daydream signer**
(`signer.daydream.live`) → `type:"lv2v"` + string `capability`; **modern
signers** (pymthouse DMZ, …) → `type:"byoc"` + BYOC capabilities
protobuf.
- `_create_byoc_payment` — assemble the payment payload + orch-discovery
capabilities per the resolved type.
- `capabilities.py` — `CapabilityId.BYOC` +
`byoc_capabilities_from_app()`.

Two files, +52/−9. Byte-identical to what runs in prod today.

## Relationship to #41
PR #41 sends `type:"byoc"` **unconditionally** and depends on an
undeployed go-livepeer signer+orch change. Against
`signer.daydream.live` (which only accepts `lv2v` today) that reproduces
the **2026-07-13 “invalid job type” outage**. This PR is the
**superset**: per-signer switching keeps the legacy signer working *and*
enables modern signers. Recommend closing #41 in favor of this.

## Follow-on
The same per-signer type logic generalizes to the **live-runner**
payment path, which will let us drop the `lr-gateway` `lv2v` workaround
once this lands.

## Test
- [ ] `python -m py_compile` (passes locally)
- [ ] `submit_byoc_job` against `signer.daydream.live` → `type:lv2v` →
200 (no regression)
- [ ] `submit_byoc_job` against a modern signer → `type:byoc` + caps
proto → 200

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@seanhanca

Copy link
Copy Markdown
Contributor Author

Superseded by #46 (per-signer dual-path) + #47 (LR path) — both merged to ja/live-runner. #46 keeps the legacy Daydream signer on lv2v; #41's unconditional type:byoc would regress it.

@seanhanca seanhanca closed this Jul 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant