Skip to content

fix: book $0 for paid calls the gateway served without settling - #94

Merged
VickyXAI merged 1 commit into
mainfrom
fix/settlement-skipped-books-zero
Oct 27, 2026
Merged

VickyXAI merged 1 commit into
mainfrom
fix/settlement-skipped-books-zero

Conversation

@VickyXAI

Copy link
Copy Markdown
Contributor

Problem

The gateways now serve some paid requests without settling them and say so on the 200:

  • sol /api/v1/pm/markets/search empty result: X-Payment-Waived: empty-result, X-Payment-Settled: false, X-Settlement-Skipped: empty-result, no PAYMENT-RESPONSE.
  • sol /api/v1/rpc/* unexecuted JSON-RPC: X-Payment-Settled: false, X-Settlement-Skipped: unexecuted.
  • chat free fallback: X-Settlement-Skipped: free-fallback.
  • base pm route: X-Payment-Waived: empty-result.

The SDK recognised none of these. Every paid retry booked the full quote, so get_spending(), the max_session_cost budget, _last_call_cost, the cost log (save_to_cache) and the tx log overstated spend for calls that moved no money. A skipped call could even push a later real call over the session limit.

Change

  • blockrun_llm/tx_log.py: settlement_skipped(headers) -> bool returns True when X-Settlement-Skipped is present with a non-empty value, or X-Payment-Waived is present. Lookup is case-insensitive over httpx.Headers or a plain dict, and it never raises. booked_cost_usd(headers, cost) returns 0.0 when skipped, otherwise cost.
  • X-Payment-Settled: false alone is not a skip marker. It means settlement had not landed yet and the call is still owed, so it keeps booking the full quote.
  • Every booking site goes through the helper. In each case the session total, _last_call_cost, save_to_cache cost and _log_transaction cost all come from the gated value:
    • client.py (Base/EVM): _booked_cost/_book_paid_call take skipped=. When skipped they return (0.0, "settlement_skipped") and release an upto hold, because that permit will never settle. The sites are sync chat stream, sync chat, sync raw POST, sync raw GET, async chat stream, async chat, async raw POST and async raw GET.
    • solana_client.py: the sites are sync and async chat stream, chat, raw POST, raw GET, inline image (200), settle-at-submit image (202, gated on the submit response) and video completion poll (gated on the completed poll).
  • The chat free fallback had no existing handling in this SDK, so it now books $0 through the same helper.
  • A 200 that has a skip marker and no PAYMENT-RESPONSE does not raise or warn. The tests assert no warnings and empty stderr.
  • No version bump. The CHANGELOG gets an ## Unreleased entry, following the repo's convention.

Tests

tests/unit/test_settlement_skipped.py has 81 tests:

  • Helper: each gateway marker shape, lowercase keys, empty values, X-Payment-Settled: false alone, None input and a broken mapping.
  • Each booking site above, across 3 cases: skipped → $0, no raise and no warning. X-Payment-Settled: false alone → full $1 booked. Normal paid → full $1 booked. Each test asserts the session total, _last_call_cost, the save_to_cache cost and the _log_transaction cost. Sync sites also check get_spending() and chat checks resp.cost_usd.
  • Spend-limit accounting (EVM and Solana): two skipped $1 calls followed by a real $1 call stay under max_session_cost=1.5. A fourth call is refused.

Results

  • Proof the tests catch the bug: I reverted client.py, solana_client.py and cache.py and confirmed by grep that 0 references to the helper were left. 24 failed, 57 passed: every site's skipped case plus both spend-limit tests. The tests that still passed are the helper tests and the control cases, which should behave the same before and after the fix. After restoring the files, 81 passed and git diff showed only the intended changes.
  • pytest tests/unit: 1423 passed.
  • black --check .: 107 files unchanged. ruff check .: all checks passed. node scripts/sync-brand-numbers.mjs --check: up to date.
  • mypy blockrun_llm (not in CI): 247 errors on both main and this branch, so none are new.
  • The llama-index integration suite was not run locally because llama_index.core is not installed in this env. CI installs it.
  • The paid API was not called.

🤖 Generated with Claude Code

The gateways now answer some paid requests without settling and say so on
the 200: X-Settlement-Skipped (empty-result on an empty sol pm result,
unexecuted on an unexecuted sol rpc call, free-fallback on a chat free
fallback) or X-Payment-Waived (sol and base pm routes). The SDK ignored both
and booked the full quote, so get_spending(), the max_session_cost budget,
_last_call_cost, the cost log and the tx log overstated spend.

Add tx_log.settlement_skipped(headers) (case-insensitive) and
booked_cost_usd(headers, cost), and route every booking site through them:
EVM sync/async chat, chat stream, raw POST and raw GET; Solana sync/async
chat, chat stream, raw POST, raw GET, inline image, settle-at-submit image
and video completion poll. X-Payment-Settled: false alone still books the
quote: settlement had not landed yet, the call is still owed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@VickyXAI
VickyXAI merged commit 42dc8a8 into main Oct 27, 2026
6 checks passed
@VickyXAI VickyXAI mentioned this pull request Oct 27, 2026
VickyXAI added a commit that referenced this pull request Oct 27, 2026
A paid call the gateway served without settling (X-Settlement-Skipped,
X-Payment-Waived) now books $0 (#94).

Co-authored-by: 1bcMax <viewitter@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
VickyXAI pushed a commit that referenced this pull request Oct 27, 2026
A settlement receipt beats a skip marker; false/0/no/none are not a skip (#96).
First PyPI release of 1.21.2's change (#94): 1.21.2 was never published.
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