refactor(usage): address round-1 review on PR #871

- store: add optional `enabled` param to record_usage_event so hot-path
  callers (nc_semantic_search) pass the already-resolved flag instead of
  forcing a second uncached Settings build (ADR-024); falls back to
  get_settings() when None so the store stays self-gating for standalone
  use.
- hooks: thread enabled= through both call sites; bump the outer
  shared()/construction failure log from debug → warning so "metering
  enabled but no billing data" is visible at the default INFO level.
- migration: instantiate postgresql.JSONB() to match the sibling
  TIMESTAMP(timezone=True) column.
- tests: fix the misleading "asyncpg returns JSONB as a JSON string"
  comment; add occurred_at dialect round-trip test and an enabled-param
  short-circuit test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-06-07 15:20:41 +02:00
co-authored by Claude Opus 4.8
parent 1c6b1a84ea
commit 702f66e6b1
6 changed files with 84 additions and 5 deletions
+10 -1
View File
@@ -72,6 +72,7 @@ class UsageEventStore:
occurred_at: datetime | None = None,
metadata: dict[str, Any] | None = None,
event_id: str | None = None,
enabled: bool | None = None,
) -> None:
"""Record one billable usage event (best-effort, flag-gated).
@@ -86,8 +87,16 @@ class UsageEventStore:
metadata: Optional rawest-unit context (provider, model, tokens,
doc_type, ...). Stored as JSONB (Postgres) / JSON text (SQLite).
event_id: Optional idempotency key; defaults to a fresh UUID4.
enabled: The resolved ``USAGE_METERING_ENABLED`` value. ``None``
(default) re-reads it via ``get_settings()`` so the store stays
self-gating for standalone/test use. Hot-path callers that
already hold the flag should pass it to avoid a second uncached
``Settings`` build (``get_settings()`` is non-cached per
ADR-024 and ``nc_semantic_search`` is on the query path).
"""
if not get_settings().usage_metering_enabled:
if enabled is None:
enabled = get_settings().usage_metering_enabled
if not enabled:
return
start = time.time()