feat: usage metering + monthly quota primitive (usage_metering.py)#198
Open
seonghobae wants to merge 1 commit into
Open
feat: usage metering + monthly quota primitive (usage_metering.py)#198seonghobae wants to merge 1 commit into
seonghobae wants to merge 1 commit into
Conversation
Durable per-API-key usage counters (conversions, input/output bytes) backed by stdlib sqlite3 in WAL mode, bucketed by YYYY-MM period, with quota enforcement via check_quota() raising QuotaExceededError that names the exceeded limit. Callers inject 'now' for deterministic tests. Includes admin helpers reset() and all_usage(period). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CJRVbDrp1vGYkJgNHMGPpG
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
codec-carver has API-key auth (who is calling) but nothing between that and billing (how much they owe). This PR adds the missing monetization primitive: durable per-key usage metering with monthly quota enforcement. It is the foundation for tiered plans (e.g. free = 50 conversions/month, pro = 10 GB/month) and for billing exports.
What
New stdlib-only module
usage_metering.py(no existing files touched):UsageStore(db_path)— SQLite-backed (WAL mode), thread-safe via short-lived connections plus a process lock. Schema:usage(api_key, period, conversions, input_bytes, output_bytes, PRIMARY KEY(api_key, period))withperiod = "YYYY-MM".record(api_key, *, input_bytes, output_bytes, now)— atomically increments the current period's counters via SQL upsert.nowis injected by the caller (the module never callsdatetime.now()), so behavior is deterministic and testable.usage(api_key, now)— current-period totals; unknown keys report zero.check_quota(api_key, now, *, max_conversions=None, max_bytes=None)— returnsTrueif allowed; raisesQuotaExceededErrorcarryinglimit_name,limit, andusedso callers/API responses can say exactly which limit was hit.reset(api_key)/all_usage(period)— admin and billing-export helpers.ValueErrorfor malformed db paths (missing parent dir, path is a directory) and negative byte counts.Tests
tests/test_usage_metering.py— 21 tests on a tmp sqlite file with injectednow, no network:QuotaExceededErrornames the limit; quota resets in a new periodrecord()from 8 threads sums correctly (200 increments)Gates
python3.14 -m unittest discover -s tests: 134 tests, no new failures (only the 5 pre-existing macOSos.listxattrerrors from baseline)python3.14 -m interrogate -c pyproject.toml usage_metering.py: 100% docstring coverage (PASSED)🤖 Generated with Claude Code