Skip to content

fix(heartbeat): record cost_cents for subscription_included events#200

Open
om952 wants to merge 1 commit into
OpenScanAI:masterfrom
om952:fix/issue-27-subscription-cost-events
Open

fix(heartbeat): record cost_cents for subscription_included events#200
om952 wants to merge 1 commit into
OpenScanAI:masterfrom
om952:fix/issue-27-subscription-cost-events

Conversation

@om952

@om952 om952 commented Jun 30, 2026

Copy link
Copy Markdown

Summary

Heartbeat cost events with billing type subscription_included were incorrectly stored with cost_cents = 0 because normalizeBilledCostCents returned 0 for that billing type. This fix removes the early return and adds a historical backfill migration.

Changes

  • server/src/services/heartbeat.ts

    • Remove the subscription_included early return in normalizeBilledCostCents.
    • Export normalizeBilledCostCents for focused unit testing.
    • All billing types now compute Math.max(0, Math.round(costUsd * 100)).
  • server/src/tests/heartbeat-cost-cents.test.ts

    • Regression tests for non-numeric inputs, metered_api, subscription_included, subscription_overage, negative clamping, and NaN/Infinity.
  • packages/db/src/migrations/0087_backfill_subscription_included_cost_cents.sql

    • Backfills cost_events.cost_cents from heartbeat_runs.result_json for rows where billing_type = 'subscription_included' and cost_cents = 0.
    • Handles cost field variants: costUsd, cost_usd, total_cost_usd.
    • Uses ROUND(cost * 100) and clamps to >= 0.
  • packages/db/src/migrations/meta/_journal.json

    • Registers migration 0087.
  • packages/db/src/backfill-subscription-included-cost-cents.test.ts

    • Embedded-Postgres tests verifying the backfill migration applies correctly and is idempotent.

Verification

  • heartbeat-cost-cents.test.ts: 6/6 passed
  • costs-service.test.ts: 16/16 passed
  • monthly-spend-service.test.ts: 2/2 passed
  • backfill-subscription-included-cost-cents.test.ts: 3/3 passed
  • packages/db migration numbering check and build: passed

Notes

  • agents.spent_monthly_cents and companies.spent_monthly_cents are hydrated from current-month cost_events on read, so correcting historical cost_events automatically corrects displayed spend.

Fixes #27

- Remove early return that forced cost_cents=0 for subscription_included.
- normalizeBilledCostCents now rounds costUsd*100 for all billing types.
- Add focused unit tests for the normalization helper.
- Add migration 0087 to backfill historical cost_events from heartbeat_runs.result_json.
- Add embedded-Postgres tests for the backfill migration.

Fixes OpenScanAI#27
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.

bug: subscription_included cost_events store cost_cents=0 — budget gates can't fire

1 participant