Skip to content

fix: skip the billing drain wait when the gateway has no receipts - #229

Open
Lotus015 wants to merge 1 commit into
mainfrom
fix/billing-skip-drain-without-receipts
Open

Lotus015 wants to merge 1 commit into
mainfrom
fix/billing-skip-drain-without-receipts

Conversation

@Lotus015

Copy link
Copy Markdown
Collaborator

Fixes #220

Summary

This takes the issue's second option: the client learns that receipts are unavailable, then skips the wait and the message. It does this without the rejected "shorten on an empty first pull" heuristic.

  • Signal. BillingReceiptFeedClient records whether each valid feed page carries x-baro-billing-receipts: authoritative. It is exposed as feed.authoritativeReceipts, with the constants BILLING_RECEIPTS_HEADER and BILLING_RECEIPTS_AUTHORITATIVE exported.

  • Drain. GatewayBillingCoordinator.drain() stops waiting early when both of these hold:

    • a feed pass that started inside drain() has succeeded without that header. A pull already in flight when drain began does not count.
    • the local measurement outbox is empty.

    Receipts that pass returns are still ingested and settled as before. A gateway that sends the header keeps the full bounded wait (5 s by default), so reconciliation does not get weaker once receipts are enabled.

  • Result. GatewayBillingDrainResult gains receiptsUnavailable. complete stays honest: unreceipted invocations remain unresolved, so their cost stays unknown and is never recorded as zero.

  • Message. orchestrate.ts ([billing] N invocation(s) remain without acknowledged authoritative telemetry) and the planning helpers run-planner, run-intake, run-conversation and run-architect (billing reconciliation incomplete) no longer report when receiptsUnavailable is true. Feed errors, timeouts and gateways that advertise receipts still report.

  • Docs. docs/collective-runtime.md documents the header.

Why a header rather than inference

Today the gateway proxies /v1/billing/receipts to Cloud. Cloud returns a well-formed empty page whether or not authoritative billing is on, so the feed body cannot tell "not enabled" apart from "not arrived yet". The gateway is the only party that knows whether it finalizes receipts (BARO_GATEWAY_BILLING_SECRET is set), so it should say so.

Follow-up needed in baro-gateway (not in this repo)

Before or together with enabling authoritative billing, handleReceiptFeed in baro-gateway/src/server.mjs should send the header on feed responses:

res.writeHead(cloud.status, {
    "content-type": cloud.headers.get("content-type") || "application/json",
    "cache-control": "no-store",
    ...(BARO_GATEWAY_BILLING_SECRET ? { "x-baro-billing-receipts": "authoritative" } : {}),
})

If billing were enabled without the header, the client would still catch every receipt for completed calls in its final feed pass, because the gateway finalizes a receipt before the model response completes. It would only stop waiting for receipts of calls aborted mid-flight.

Test plan

  • New coordinator tests in test/telemetry/billing/gateway-billing-coordinator.test.ts:
    • No header: drain returns in well under 1 s despite drainTimeoutMs: 5000, with receiptsUnavailable: true and no feedError.
    • No header but the receipt is present: still settles, complete: true.
    • Header present: drain keeps polling until its deadline, with receiptsUnavailable: false.
    • A successful pull that predates drain(), followed by failing pulls, does not conclude that receipts are unavailable.
  • node --test test/telemetry/billing/*.test.ts: 35/35 pass, including the existing coordinator, feed and activation tests.
  • npm run typecheck -w @baro/orchestrator passes. A separate tsc check of the four touched scripts/run-*.ts files reports no errors.
  • npm run build -w baro-ai (tsup bundle) succeeds.
  • npm run test:fast: 1640/1647 pass. The 7 failures are in provider-ownership-manifest, run-architect-awake-budget, verification/command-timing and verification/continuous-gate-runner. These are timing and process-group tests. Run alone, 5 of them still fail on this branch and the same 5 fail with src/ reset to origin/main, so they are environmental and predate this change.
  • Slow-lane run-architect-outcome and conversation/dialogue-responder: 32/33 pass. The Gateway billing test passes; the one failure is the same Codex wall-clock timing issue as above.
  • Not run: npm run test:billing-e2e, which needs sibling baro-cloud and baro-gateway checkouts. Its receipt arrives on the first drain pass, so it should be unaffected.
  • Not run: the complete npm test suite. Both attempts were cut off by the tool's process cleanup before finishing, so only the fast lane and the two slow-lane files above have results.

Generated with Devin

Every gateway run waited out the 5 s drain deadline and then printed
"N invocation(s) remain without acknowledged authoritative telemetry",
because the gateway's authoritative receipts are not enabled and no receipt
ever arrives. The receipt feed now has to advertise
`x-baro-billing-receipts: authoritative` for the drain to keep waiting.
Without it, Baro still ingests whatever one feed pass started inside drain()
returns, then stops and does not report the gap as a reconciliation failure.
A gateway that advertises receipts keeps the full bounded wait.

Fixes #220

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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.

Gateway runs always end with "N invocation(s) remain without acknowledged authoritative telemetry"

1 participant