Skip to content
FluxMeter
中文

v3.2.2 · 40 releases

Changelog

Full release history for the open-source engine — synced from changLog.md.

v3.2.0

Added

  • Gateway MVP (api/gateway/, gateway_app.py): OpenAI-compatible proxy on :8080 with pre-check, stream reserve, mid-flight kill, proxy-only ingest
  • Shared budget gate (api/budget_gate.py) — /check and Gateway reuse same logic
  • Docs: docs/gateway.md, demos/gateway_demo.py
  • Docker: gateway service in lite compose; Dockerfile copies full api/ tree (fixes Intelligence module gap)

Changed

  • Engine / API / Gateway version 3.2.0; Phase G P1 complete (P2 LiteLLM/TPM/predictive deferred)
  • make demo prints Gateway URL; make demo-gateway for mock self-check

Notes

  • Stream kill uses heuristic token estimate when provider omits usage chunks (same as SDK wrap())
  • Helm gateway deployment deferred to Phase G.1 — same image, uvicorn gateway_app:app

v3.1.0

Added

  • Pricing Optimizer: GET /intelligence/pricing-recommendations — rule-based price increase / model switch with annual ROI
  • Profitability Dashboard: GET /intelligence/profitability — cross-customer margin, product breakdown, multi-month trend
  • Spend Forecast: GET /intelligence/forecast — linear EOM projection vs budget
  • Anomaly Alerts: background worker + POST /intelligence/alerts/webhook — INTEL_COST_SPIKE, INTEL_MARGIN_LOSS, INTEL_FORECAST_RISK
  • Report Export: GET /intelligence/report?format=markdown|json — Finance/CEO one-pager
  • Native reader extensions: daily costs, global period trends, dim margin series

Changed

  • Engine / API version 3.1.0; Phase 6 Intelligence v1.0 complete
  • docs/intelligence-api.md — Phase 6 endpoints

Notes

  • Alert webhook: FLUXMETER_INTEL_WEBHOOK_URL env or admin POST; debounce 24h per alert type
  • Product revenue allocation uses cost-share heuristic (ponytail); per-SKU revenue deferred to Phase 7+

v3.0.0

Added

  • Intelligence MVP: root cause analysis, unit economics, scenario simulation, OpenMeter overlay ingest (api/intelligence/)
  • Model-period rollup on lite ingest (usage_buckets.py + lite_aggregate_lua.py)
  • Docs: docs/intelligence-api.md, landing copy, OpenAPI /intelligence/* paths

Changed

  • Product narrative shifts to Layer 4 (Monetization Intelligence); metering pillar retained and maintained
  • Engine / API version 3.0.0

Notes

  • Major bump = product narrative shift, not breaking API for existing metering endpoints

v2.8.0

Added

  • Multi-platform billing export: Metronome + Orb + hardened Stripe in api/billing_export.py (BILLING_EXPORT_TARGETS, idempotent deltas, Stripe retry)
  • Generic customer link: POST /admin/billing/{id}/link (platform: stripe | metronome | orb)
  • Partner recipes: docs/integrations/stripe.md, metronome.md, orb.md
  • Hierarchy reserve-confirm: POST /budget/{id}/reserve?parent_span_id= atomically holds customer + span cap pool
  • Per-key API budgets: POST /admin/customers/{id}/apikeys/{key_id}/budget; enforced on /check with customer API keys
  • Metadata dims: ingest metadata (whitelist FLUXMETER_USAGE_DIMS); GET /usage/dim/{key}/{value}?period=YYYY-MM
  • Interop spec: spec/schema/external-export-mappings.md
  • Python SDK 1.5.0: reserve(parent_span_id=) / reconcile(parent_span_id=)

Changed

  • docs/integrations.md trimmed; first-class export docs linked
  • Engine / API version 2.8.0; Phase 4 complementary export complete

Notes

  • Export tests: tests/test_billing_export_partners.py, tests/test_hierarchy_reserve.py (requires lupa for fakeredis Lua)

v2.7.1

Fixed

  • RedisSink crash window: SET NX + pipeline replaced with a single Lua EVAL (idempotency + counters + rollup) so a mid-flight crash cannot leave applied:* set without writes

Added

  • Flink harness tests: LateDataSideOutputTest (watermark → late side output, no allowedLateness), WindowMetadataFunctionTest, RedisSinkIdempotencyTest (Redis-gated)
  • TEST_PLAN #2: TestIdempotency.test_window_replay_set_nx_not_double_counted (window SET NX replay)
  • make correctness-bench: known-event cost/counter assertion + Flink checkpoint health summary

Changed

  • Checkpoint config: explicit EXACTLY_ONCE, 10m timeout, tolerableCheckpointFailureNumber(3)
  • Docs: EO semantics in load-testing.md; progress.md late-data note aligned with code (no allowedLateness → DLQ)

Notes

  • Engine version 2.7.1; Java tests need --add-opens for Flink serializers on Java 17+

v2.7.0

Added

  • Lite budget webhooks: BUDGET_LOW / BUDGET_EXHAUSTED / BUDGET_WARN fire on /ingest without Kafka (api/webhook_deliver.py)
  • Soft alert ladder: BUDGET_WARN at 70% and 90% of (initial_balance + topups) spent (warn_pct, spent_pct in payload; BUDGET_WARN_PCTS env)
  • Python wrap(OpenAI()): pre-call check, post-call track, fail-open; mid-stream StreamKilledError when est cost exceeds reserve (SDK 1.4.0)
  • HTTP-mode Python SDK: FluxMeter(api_url=...) for Lite ingest / check / reserve (no Kafka dependency)
  • Hierarchy caps: POST /budget/{id}/cap + check?parent_span_id= / session_id= enforce span/session hard max spend
  • Path activation demo: demos/path_activation_demo.py (self-check + optional --live)
  • JS SDK 1.3.0: built for npm (sdk/js)

Changed

  • Engine / API version 2.7.0; Phase 3 path activation complete (npm registry push optional if unauthenticated)

Notes

  • Full-mode webhooks still use Kafka webhook-worker; Lite shares HMAC payload shape
  • Python SDK 1.4.0 on PyPI

v2.6.2

Added

  • Lite span aggregation: parentSpanId on /ingest increments span:{id}:* counters (mirrors Flink SpanSink schema); GET /usage/span/{id} and /usage/customer/{id}/spans work on Lite path
  • usage_buckets.increment_span: 24h TTL, customer ZSET by cost, duration from first/last event timestamps

Changed

  • Docs: customer-integration-lite.md §6.1 marked shipped; api-reference billing guide notes Lite span support

Notes

  • Span keys use INCRBY (per-event delta); Full Flink path still SETs window totals — query API shape is identical

v2.6.1

Added

  • Period/day usage queries: GET /usage/customer/{id}/period/{YYYY-MM}, GET /usage/customer/{id}/day/{YYYY-MM-DD} — reads Redis rollup buckets (lite rollup worker + Flink RedisSink)
  • Session usage query: GET /usage/session/{id} — lite ingest aggregates by sessionId (90d TTL, configurable)
  • api/usage_buckets.py: shared rollup key helpers and session counters

Changed

  • Docs / OpenAPI: period, day, session query endpoints; billing query guide; semantic conventions; integrations table

Fixed

  • Dockerfile: include usage_buckets.py (lite API crash on v2.6.1 deploy)
  • Flink job submit: tier volume state moved to MonthlyVolumeStampFunction (Flink rejects RichFunction in aggregate+ProcessWindowFunction)
  • SaaS compose: wire FLUXMETER_API_KEY / FLUXMETER_ADMIN_KEY for auth-enforced API tests
  • Tests: E2E harness uses 127.0.0.1 (macOS localhost → IPv6 503); pricing admin test restores catalog; rerate apply timeout 120s

Notes

  • Full-mode session aggregation still lite-only on ingest; Kafka/Flink path unchanged (use parentSpanId for tasks)
  • Day/month buckets accumulate from deploy forward; no historical backfill

v2.6.0

Added

  • Chinese domestic model pricing: 20 models across DeepSeek, Qwen, GLM, Moonshot, Doubao, Baichuan, MiniMax, Hunyuan in config/pricing.json
  • SDK track helpers: track_deepseek, track_qwen, track_glm, track_moonshot, track_doubao, track_baichuan, track_minimax, track_hunyuan (Python + JS)
  • Provider docs: 8 mapping guides in contrib/providers/ + contrib/pricing/china-2026-07.json
  • LoadGenerator: DeepSeek, Qwen, GLM, Moonshot in demo traffic mix

Changed

  • Python SDK → 1.3.0; JS SDK → 1.2.0
  • Pricing catalog version 2, effective 2026-07-01

Notes

  • Qwen Plus/Max use flat base-tier pricing; >256K input tier surcharges documented in contrib
  • hunyuan-lite priced at $0 (free tier)

v2.5.0

Added

  • Stripe export modes: STRIPE_EXPORT_MODE=events|cost, BILLING_EXPORT_PERIOD=hourly|monthly
  • Rollup month buckets: rollup:{customer}:period:{YYYY-MM} aligned to billing calendar
  • Prepaid token packages: POST/GET /budget/{id}/package + lite ingest drawdown
  • Stripe Checkout: POST /tenants/{id}/checkout on control plane
  • Flink → Redis period sync: RedisSink increments period:*:volume_tokens
  • Docs: docs/pricing-hybrid-paths.md
  • Tests: test_tier_e2e.py, test_phase2_billing.py

Changed

  • Python SDK → 1.2.0 (engine 2.5.0 compatible; no breaking API changes)
  • Version alignment: engine, API, OpenAPI, Helm, control plane → 2.5.0
  • Phase 2 ROADMAP items marked complete (tier pricing shipped in 2.4.0)
  • Link audit: README/SDK metadata — fluxmeter.dev for marketing site only; technical docs → GitHub docs/; PyPI Documentation URL fixed (was duplicate homepage)
  • README / PyPI positioning: marketing snippet at README top (website + blog links, use-case line, license badge); PyPI description + keywords synced from marketing snippet

v2.4.0

Added

  • Tiered pricing engine: pricing_mode flat | volume | graduated in PricingCatalog (Java) and api/pricing_loader.py (Lite)
  • Lite volume tracking: Redis period:{YYYY-MM}:volume_tokens + atomic tier cost in Lua (lite_aggregate_lua.py)
  • Flink volume state: UsageAggregateFunction with keyed ValueState + MonthlyVolumeMeter
  • Example catalog: contrib/pricing/tiered-example.json
  • Tests: PricingCatalogTest, UsageAggregateTierTest, MonthlyVolumeMeterTest, test_pricing_loader.py, Lite Redis tier tests
  • Re-rating guard: /rerate/* returns 422 for non-flat models

Changed

  • Pricing API validation: monotonic tiers, open-ended last tier, volume_scope / billing_period checks
  • Version alignment: engine, API, OpenAPI, Helm → 2.4.0
  • Docs: tier pricing in docs/api-reference.md; re-rating + tier replay in docs/integrations.md

Notes

  • Default config/pricing.json stays flat — no behavior change until you opt into a tier catalog
  • Span attribution (parentSpanId windows) still uses flat tier selection (volume meter is customer|model scoped)
  • Phase 2 Stripe Checkout wiring remains on ROADMAP; tier pricing P0 is complete

v2.2.2

Added

  • api/tenant_keys.py: Python mirror of TenantKeys.java for lite Redis key prefixes
  • tests/test_tenant_keys.py: no-Redis unit tests for tenant key helpers
  • make test-unit-redis: lite Lua aggregator + rollup tests (requires local Redis)
  • Lite multi-tenant ingest: optional tenantId on /ingest events; Lua global counters scoped per tenant
  • Tenant E2E: test_lite_production.py::TestTenantIsolation (HTTP ingest + Redis key prefix)

Changed

  • Official website links: README, SHOW_HN, CONTRIBUTING, SDK READMEs, pyproject.toml / package.json → fluxmeter.dev; README integrations list includes Stripe
  • make test-unit: runs auth, billing export, control-plane models, tenant_keys + ./gradlew test
  • OpenAPI 2.2.2: health mode, lite/full ingest response schemas, POST /admin/billing/{id}/link-stripe
  • validate-spec.sh: checks OpenAPI completeness (mode, cost_usd, link-stripe, batch lite schema)
  • docs/load-testing.md: Mac ~25K sustained @ 50K target callout in Quick start
  • Version alignment: engine, API, OpenAPI, Helm → 2.2.2

Fixed

  • Lite API Docker image: include tenant_keys.py (import required by lite_aggregate_lua.py)
  • Lua budget return: return balance as string so Redis script replies preserve sub-cent amounts

Notes

  • Phase 1 (ROADMAP v2.3 polish) complete; tiered pricing runtime remains Phase 2 / v2.4.0
  • Single-tenant behavior unchanged when tenantId is omitted

v2.2.1

Added

  • JUnit tests for Java financial core: PricingCatalogTest, UsageAggregateTest, TenantKeysTest, TokenEventTest, AggregationKeysTest; make test-java
  • AggregationKeys utility (io.fluxmeter.util): parses Flink window keys (customer|model lite, tenant|customer|model SaaS) into UsageAggregate fields
  • Python unit tests (no Docker): tests/test_lite_aggregate_unit.py (Lua aggregator idempotency, pricing, inline budget); tests/test_control_plane_models.py (plan tiers, defaults)
  • Unified E2E runner: scripts/run-e2e-all.sh — unit → lite → full Flink → SaaS stacks (--unit-only, --lite-only, --full-only)
  • Control plane API reference: docs/control-plane-api.md — tenant CRUD, plans, auth, usage queries
  • Flink Prometheus metrics: custom flink/Dockerfile with Prometheus reporter JAR; prometheus service in docker-compose.full.yml (:9090)
  • Disaster recovery runbook: docs/disaster-recovery.md — Redis loss, Flink replay, Kafka WAL, lite mode recovery
  • Multi-tenant Flink isolation: optional tenantId on TokenEvent; aggregation key tenantId|customerId|modelId; Redis keys via TenantKeys utility
  • PyPI Python SDK 1.1.0: latest fluxmeter package published — https://pypi.org/project/fluxmeter/1.1.0/ (pip install fluxmeter)

Changed

  • ROADMAP.md: project-wide forward plan (phases v2.3 → v3.x, ecosystem track, non-goals)
  • Version alignment across repo: Python/JS SDK 1.1.0 (PyPI/npm source); engine, API, OpenAPI, Helm, control plane → 2.2.1

Notes

  • Single-tenant deployments unchanged when tenantId is omitted (keys remain customer:{id}:*)
  • Load test (3 TM, 12 parallelism, 2026-06-22): ~25K avg eps at 50K target tier; Redis Lua sink remains local bottleneck above ~100K sustained

v2.2.0

Added

  • SaaS control plane (services/control-plane/): FastAPI tenant CRUD on :8001 — create/list/delete tenants, plan tiers (free/growth/scale/enterprise), API key provisioning, usage queries via shared Redis
  • docker-compose.saas.yml: Lite stack + control plane + password-protected Redis; make start-saas / make stop-saas
  • Control plane tests (tests/test_control_plane.py): tenant lifecycle and plan limit enforcement
  • Stripe billing stub (services/control-plane/stripe_billing.py): subscription creation scaffold for future webhook integration

Notes

  • Control plane shares Redis with main API for tenant-scoped rate limits (tenant:{id}:max_eps, tenant:{id}:max_events_month)

v2.1.0

Added

  • Atomic Lua lite aggregator (api/lite_aggregate_lua.py): single-script idempotency, counter increments, global counters, and inline budget deduction (replaces non-atomic pipeline in lite mode)
  • Background rollup worker (api/rollup_worker.py): asyncio task compacts live counters into per-minute Redis hashes (24h TTL) and resets live counters every 60s in lite mode
  • Rollup tests (tests/test_rollup.py): counter compaction logic against Redis
  • Stripe billing export (api/billing_export.py): hourly usage reporting to Stripe Billing Meters API; admin endpoint POST /admin/billing/{customer_id}/link-stripe
  • Billing export tests (tests/test_billing_export.py): mocked Stripe, no infra required

Changed

  • /ingest and /ingest/batch (lite mode): return JSON with status, cost_usd, balance_usd; batch returns {"results": [...]}
  • Model keys in lite mode: use normalize_model_id() (aligned with Flink sink)

Notes

  • api/lite_aggregate.py retained for backward compatibility; lite ingest path uses lite_aggregate_lua.py

v2.0.2

Fixed

  • Budget API 500: POST /budget/{id} called get_customer_budget() directly; FastAPI Header default leaked as API key → AttributeError. Extracted _fetch_customer_budget() for internal reuse.

Changed

  • Lite as default DX: docker-compose.yml is lite stack; full Flink/Kafka stack in docker-compose.full.yml. make demo runs lite; make demo-full runs full stack. demo-lite / start-lite remain aliases.
  • docker-compose.full.yml high-throughput profile: 3 TaskManagers (4 slots × 5G each), Redis 4G + io-threads, Kafka 24 partitions + network tuning, kafka-init service; mem_limit + restart: unless-stopped
  • Load test defaults: NUM_THREADS=8, FLINK_PARALLELISM=12; Makefile submit-job -p 12

Notes

  • Local target: 100K eps sustained, 1M eps burst (Redis Lua sink remains bottleneck above ~100K avg)

v2.0.1

Added

  • E2E test suite: tests/test_e2e_v2.py — v1.2–v2.0 scenarios (single-path billing, API keys, debt floor, pricing API, reconciliation, webhooks)
  • Unit tests: tests/test_auth_unit.py — customer key tenant isolation
  • Load test script: scripts/load-test.sh, make load-test / make load-test-quick
  • Docs: docs/load-testing.md, tests/TEST_PLAN.md §11–16

Fixed

  • Flink job submission: RichAggregateFunction incompatible with window.aggregate() on Flink 1.18 — reverted to plain AggregateFunction (job runs again)
  • Customer API key isolation: mismatched customer key always returns 403 (not bypassed in demo mode)
  • docker-compose.yml: Grafana service YAML nesting error

Changed

  • Tiered pricing: PricingCatalog tier schema remains; engine applies first tier until monthly volume tracking lands (no RichAggregateFunction state)

Notes

  • Load test (local docker-compose): ~50K eps sustained; 500K+ target limited by single TaskManager + Redis on dev hardware
  • Java engine 2.0.1

v2.0.0

Added

  • Helm chart: deploy/helm/fluxmeter — API deployment, Service, PrometheusRule alerts (lag, window stall, reconciliation drift)
  • Tiered pricing schema: PricingCatalog supports per-model volume tiers in JSON/YAML
  • Deploy docs: deploy/helm/README.md

Notes

  • Java engine 2.0.0; production assumes external Kafka/Redis + Flink Operator

v1.4.0

Added

  • Balance reconciliation job: jobs/reconcile_balances.py — balance == initial + topups - total_deducted; stores snapshot in reconciliation:last
  • DLQ replay: scripts/dlq_replay.py, scripts/replay-dlq.sh
  • Runbook: docs/runbooks/dlq-replay.md
  • API: GET /admin/reconciliation
  • docker-compose: reconcile-job service

v1.3.0

Added

  • External pricing: io.fluxmeter.pricing.PricingCatalog loaded from config/pricing.json or classpath
  • Pricing API: GET /pricing, PUT /admin/pricing, POST /admin/pricing/validate
  • UsageAggregate decoupled from hardcoded switch pricing

Changed

  • Flink UsageAggregateFunction uses PricingCatalog (flat rate per event; tier selection deferred to 2.0.1+)

v1.2.0

Added

  • Single-path balance deduction: reserve/reconcile use held_usd only; Flink Sink sole balance_usd mutator
  • Debt tracking: excess cost recorded in budget:{id}:debt_usd when balance floors at zero
  • Customer API keys: POST /admin/customers/{id}/api-keys, per-customer ingest/check authorization
  • Budget webhooks: POST /budget/{id}/webhook + webhook-worker Kafka consumer → HTTPS with HMAC
  • Budget fields: held_usd, effective_balance_usd, debt_usd on budget responses

Fixed

  • Streaming double-charge: reserve no longer deducts balance before Sink window deduction
  • Reconcile negative balance: reconcile releases hold only; no balance credit/debit

Changed

  • check uses effective_balance = balance - held

v1.1.0

Added

  • OpenCore repo split: spec/ (JSON Schema, OpenAPI, semantic conventions, pricing template)
  • Community layer: contrib/ with provider mappings, pricing snapshot, CONTRIBUTING
  • JavaScript SDK: sdk/js (@fluxmeter/client) — HTTP ingest + optional Kafka
  • Lite demo: default docker-compose.yml + make demo — Redis + API + Grafana, no Flink/Kafka (make demo-full for Flink stack in docker-compose.full.yml)
  • Lite aggregation: api/lite_aggregate.py — per-event Redis counters matching full stack key schema
  • Spec validation: scripts/validate-spec.sh, make validate-spec
  • Engine docs: src/README.md — reference implementation boundary

Changed

  • API Dockerfile builds from repo root (includes spec/ for /openapi.yaml)
  • README: OpenCore layout, lite vs full quick start, JS SDK examples
  • Java engine version 1.1.0

Notes

  • Python SDK: pip install fluxmeter — 1.1.0 on PyPI (2026-06-22); JS SDK build with cd sdk/js && npm run build

v1.0.0

Added

  • Python SDK PyPI release: fluxmeter 1.0.0 on PyPI (sdk/python/pyproject.toml aligned with __version__)
  • CI publish workflow: .github/workflows/pypi-publish.yml (Trusted Publisher → PyPI)
  • Release docs: docs/pypi-release.md (manual + TestPyPI + CI steps)

Changed

  • Python SDK classifier: Production/Stable; Java engine version 1.0.0

Notes

  • Published on PyPI: https://pypi.org/project/fluxmeter/1.0.0/ — pip install fluxmeter
  • Configure PyPI Trusted Publisher for CI (no tokens in git). See docs/pypi-release.md.

v1.0.0-rc3

Fixed

  • WAL partial batch duplicate: flush sends one event at a time; offset advances only after Kafka ack
  • WAL exit data loss: flush() drains WAL synchronously before close
  • Redis password in prod: REDIS_PASSWORD wired to API (ConnectionPool) and all Java sinks via RedisConnections
  • Checkpoint disabled in submit-job: Flink containers chown checkpoint volume; removed CHECKPOINT_DIR= override from Makefile
  • Integration test flakiness: budget accuracy uses 180s poll + multi-model watermarks; idempotency reordered before heavy load with keepalive watermarks; push_watermarks aligned to 10s Flink window (12s interval)

Notes

  • Prod overlay E2E: 20/20 passed (5 prod auth + 15 integration) on docker-compose.prod.yml stack

v1.0.0-rc2

Fixed

  • Fractional model pricing: calculateEventCostMicro uses Math.round(tokens * pricePerM) — sub-$1/M models no longer bill as $0
  • Model ID normalization: versioned IDs (e.g. gpt-4o-2024-08-06) map to canonical pricing keys via prefix match
  • Streaming heartbeat double-billing: Flink filters _heartbeat metadata; SDK heartbeats emit delta tokens only
  • WAL duplicate Kafka sends: WAL-enabled clients send only via flush loop with byte-offset tracking
  • BudgetEnforcerSink crash window: single Lua script atomically sets idempotency key, writes counters, and deducts budget
  • OptimizedRedisSink global counters: global totals accumulated only for windows that pass idempotency check
  • Event-level dedup: UsageAggregate tracks seenEventIds per window (bounded by window event count)

Added

  • API authentication: X-API-Key header via FLUXMETER_API_KEY / FLUXMETER_ADMIN_KEY; demo mode via FLUXMETER_AUTH_OPTIONAL=true
  • docker-compose.prod.yml: Redis password, API key enforcement, Grafana anonymous disabled, fail-closed budget policy

Changed

  • Default BUDGET_FAIL_POLICY: closed in API (docker-compose demo sets open explicitly)

Notes

  • Addresses 15 findings from Bugbot + Security Review (2026-06-21)

v1.0.0-rc1

Fixed (10 production issues)

Notes

v0.9.1

Added

  • Three-layer resilient budget check:

v0.9.0

Added

  • OptimizedRedisSink — drop-in replacement with 4 algorithmic improvements:
  • Integration test suite (10 correctness scenarios):
  • Global counter reduce operator in Flink (preparation for isolated global sink)

Notes

  • Redis keys: 100K → 10K (10x reduction)
  • Redis ops/cycle: 135K → 27K (5x reduction)
  • Idempotency memory: 54 MB → 9 MB (6x reduction)
  • Global counter writes: 9K/cycle → 180/cycle (50x reduction)

v0.8.1

Added

  • HTTP ingest endpoint (no Kafka client required):

Verified (E2E with HTTP ingest)

  • 511 events ingested via HTTP → Kafka → Flink → Redis → API query
  • Budget deducted correctly ($10 → $4.44)
  • Zero SDK or Kafka client needed for integration

Notes

v0.8.0

Added

  • Streaming mid-response — budget safety (estimated pre-deduction):
  • Streaming mid-response — SDK heartbeat (observability):
  • Retroactive re-rating — differential adjustment:

Notes

  • All 10 original requirements now complete
  • SDK version bumped to 0.7.0

v0.7.0

Added

  • Rate limiting in pre-request guardrail:

Verified (load test + requirements)

  • 1M eps sustained — 30 seconds at 1,000,000 events/sec, both TMs stable
  • All throughput tiers: 10K → 50K → 100K → 500K → 1M eps, zero failures
  • Guardrails: budget check + rate limit + alerts all working end-to-end
  • Credits drawdown: set → deduct → exhaust → deny → topup → re-allow
  • Multi-provider: 6 models verified with correct per-model pricing
  • Exactly-once: 880K idempotency keys verified in Redis (1h TTL)

Not Implemented (documented, deferred)

  • Streaming mid-response metering: requires proxy mode (SSE stream parser)
  • Retroactive re-rating: requires pricing versioning + Kafka replay job

v0.6.2

Fixed

  • CRITICAL: Removed Flink EventDeduplicator — keying by eventId created 1 key per event
  • HIGH: Removed allowedLateness(30s) — late data re-fired the window, but SET NX blocked
  • HIGH: Counter + budget deduction now atomic — customer cost_usd increment moved inside
  • MEDIUM: SpanSink uses SET (overwrite) instead of INCRBY — session windows fire multiple
  • API version updated to 0.6.1

v0.6.1

Fixed

  • Makefile JAR path: was fluxmeter-0.4.0.jar, now fluxmeter-0.6.0.jar
  • Checkpoint dir not mounted: added flink-checkpoints shared volume to
  • SpanSink missing idempotency: added SET NX gate keyed by spanId|lastEventTime
  • Late events silently dropped: LateEventSink now produces to Kafka DLQ topic

Changed

  • README: added Durability section (failure matrix), two-layer enforcement model,

v0.6.0

Added

  • SDK Write-Ahead Log (zero data loss):
  • Event deduplication (no double-billing):
  • Pre-request budget check (<10ms enforcement):
  • Redis AOF persistence:

Changed

  • SDK Kafka producer: acks=all (was acks=1) — waits for all replicas
  • SDK _send(): graceful BufferError handling (event safe in WAL, no panic)
  • SDK version bumped to 0.5.0

Production Gap Status

v0.5.0

Added

  • Exactly-once semantics:
  • Late event handling:
  • Agent span cost attribution:

Fixed

  • Budget race condition: replaced GET-then-INCRBYFLOAT with atomic Lua script
  • Null event crash: added .filter() after source for null/invalid events
  • cacheWriteTokens not priced: added to calculateEventCost() at input rate
  • Negative topup: API rejects amount_usd <= 0 with 400
  • Idle timeout increased from 10s to 30s (prevents premature watermark advance)

Changed

  • calculateCost renamed to calculateEventCost and made public (used by SpanAggregateFunction)
  • Kafka offsets: committedOffsets(LATEST) when checkpointing enabled

v0.4.0

Added

  • Budget enforcement (BudgetEnforcerSink):
  • FastAPI query endpoint (api/):
  • kafka-clients 3.7.0 explicit dependency (for alert producer)

Changed

  • Incremental aggregation: replaced ProcessWindowFunction with AggregateFunction
  • TM parallelism reduced to 2 slots (works on laptops with 4GB TMs)
  • Budget enforcement enabled by default (BUDGET_ENFORCEMENT=true)

Notes

  • End-to-end verified: $5 budget → BUDGET_LOW at $0.79 → BUDGET_EXHAUSTED at -$0.17
  • Works at 5K eps with 4GB TaskManagers (incremental aggregation is the key)
  • Alert latency: sub-second from window close to Kafka delivery

v0.3.0

Added

  • Python SDK (sdk/python/): pip install fluxmeter
  • Multi-provider event schema with 5 token categories:
  • Provider and tracing fields: provider, requestId, spanId, latencyMs, environment
  • Pricing for 9 models across 3 providers (OpenAI, Anthropic, Google)
  • Weighted model distribution in load generator (realistic traffic patterns)

Changed

  • BREAKING: Event schema — tokenType+tokenCount replaced by per-category fields
  • Renamed project: TokenFlink → FluxMeter (packages, containers, artifacts, docs)
  • README rewritten with neutral tone, architectural framing, SDK examples
  • Load generator now produces multi-provider events with cache/reasoning tokens

Removed

  • TokenType enum (replaced by explicit per-category token fields)

Notes

  • Build verified after schema change (all Java compiles clean)
  • Python SDK tests pass (event serialization + provider response parsing)
  • ClickHouse baseline SQL updated for new schema

v0.2.0

Added

  • Grafana dashboard with Redis datasource plugin (auto-provisioned, live streaming panels)
  • ClickHouse baseline comparison (Kafka engine + materialized views + SummingMergeTree)
  • make benchmark — automated Flink vs ClickHouse latency comparison
  • Terminal demo GIF (1.7MB, recorded with VHS)
  • Show HN post draft (SHOW_HN.md)
  • Apache 2.0 LICENSE file

Changed

  • Default window size from 60s to 10s (reduces memory pressure, faster feedback)
  • TaskManager memory from 6g to 8g (supports 1M eps bursts)
  • Disabled checkpointing for demo (avoids shared storage complexity in docker-compose)
  • Added fixed-delay restart strategy (10 attempts, 5s delay)

Notes

  • 500K eps sustained indefinitely on single machine (docker-compose)
  • 1M eps sustained for 30-40s bursts (JVM heap limit for window state)
  • ClickHouse baseline shows 8-43s query lag vs Flink's sub-second

v0.1.1

Added

  • docs/DESIGN.md — approved design document
  • progress.md — implementation tracker
  • changLog.md — this file

Notes

  • Documentation only, no runtime changes.

v0.1.0

Added

  • Java 17 + Gradle project with Flink 1.18.1 DataStream API
  • TokenUsageAggregator — Kafka → keyed tumbling window → Redis
  • TokenEvent and UsageAggregate models
  • LoadGenerator — Java Kafka producer targeting 1M events/sec
  • RedisSink — window-aggregated usage writes
  • docker-compose.yml — KRaft Kafka, Flink cluster, Redis, Grafana
  • Grafana Redis datasource provisioning
  • Makefile — build, demo, start, stop, clean, submit-job, generate
  • README.md — quick start and architecture overview

This page mirrors the engine changelog. Edit or browse the source file on GitHub.