Skip to content

Billing hardening follow-ups: live FX, integer ledger history, and pi-ai 0.83 #4

Description

@1amKhush

Context

Follow-up to the billing implementation in #2 and the audit in #1.

The current Phase 1 implementation is approved and working correctly. This issue tracks the non-blocking hardening work identified during maintainer review.

Workstreams

1. Live USD/sat exchange rate

Replace the operator-maintained MUXLL_USD_PER_SAT value with a live Fx.usdPerSat() service.

Proposed behavior:

  • Fetch the current USD/BTC rate using provider fallback:
    1. Kraken
    2. Coinbase
    3. Binance
  • Convert the USD/BTC rate into USD per satoshi.
  • Cache successful rates for approximately one hour.
  • Avoid making an external request for every top-up.
  • Preserve MUXLL_TOPUP_BUFFER_PCT as protection against price movement.
  • Define and document behavior when every provider is unavailable:
    • fail closed, or
    • use the last known rate with a maximum stale age.
  • Decide whether MUXLL_USD_PER_SAT remains available as an explicit operator override or emergency fallback.

Acceptance criteria

  • balance.topup uses the FX service when calculating the required sats.
  • Provider fallback order is deterministic and tested.
  • Cache expiration and reuse are tested.
  • Complete provider failure has explicit, tested behavior.
  • Invalid or non-positive provider responses are rejected.
  • No top-up is quoted using an undefined or silently invalid rate.

2. Store all ledger USD values as integer nano-dollars

Complete the integer-money representation across the ledger.

Current state:

  • balances.credit_nusd uses integer nano-dollars.
  • usage.cost_usd, usage.charge_usd, and credits.amount_usd use SQLite REAL values.

Required changes:

  • Store usage cost and charge amounts as integer nano-dollars.
  • Store credit history amounts as integer nano-dollars.
  • Convert to decimal USD only at the public API boundary.
  • Add a migration strategy for existing SQLite ledger files.
  • Update comments and documentation so they accurately describe the storage format.

Acceptance criteria

  • All persisted USD monetary values use integer nano-dollars.
  • Repeated credits and charges do not accumulate floating-point drift.
  • Existing balance, usage history, and credit history behavior remains unchanged at the API boundary.
  • Migration behavior is covered by tests.
  • AGENTS.md, ledger.ts, and billing documentation accurately describe the final representation.

3. Upgrade @earendil-works/pi-ai to 0.83.0

The workspace currently uses ^0.80.3. Because this is a 0.x dependency, the current range does not upgrade to 0.83.0.

Required work:

  • Review the 0.81.x through 0.83.0 changelog.
  • Confirm existing subpath imports remain supported.
  • Check whether any root imports need to move to @earendil-works/pi-ai/compat.
  • Update the dependency version consistently across all workspace packages.
  • Update the lockfile.
  • Run typecheck, lint, and the complete test suite.

Acceptance criteria

  • Every workspace package uses the same compatible pi-ai version.
  • No deprecated or moved root API is imported incorrectly.
  • Typecheck and lint pass.
  • The complete test suite passes without regressions.

Out of scope

The following remain intentionally deferred to billing Phase 2:

  • Fixed-rate model pricing
  • byModel pricing overrides
  • byPubkey pricing overrides

Refs #1
Follow-up to #2

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions