ADR 248 · Accepted
An extension reads its own usage through public API
Context
A consuming extension names itself on every call with withCallerSource($extensionKey, $operation) (ADR-177, ADR-178). nr_llm stores the name in two places: the daily cost aggregate tx_nrllm_service_usage (source_extension) and the per-call telemetry tx_nrllm_telemetry (source_extension, source_operation, success). The Analytics module shows cost per extension to administrators.
The cowriter and the AI chat each get an overview module that has to say what the extension cost and how often each of its actions ran and failed. The services that read those tables, UsageAnalyticsService and the telemetry repository, are internal (ADR-127). Reading the tables from the consumer would tie two other extensions to a schema that is not covered by semantic versioning.
Decision
ExtensionUsageReaderInterface is public API (@api). It answers for one source extension and a period, optionally narrowed to one backend user:
totals() — estimated cost, requests and tokens from the daily aggregate, the figures the Analytics module shows per extension.
operations() — calls and failed calls per operation, with the time of the newest call, from the telemetry.
coverage() — whether telemetry is switched on, its retention in days and the oldest stored call, so a caller can say from when the per-operation counts are complete.
It is a new interface rather than new methods on UsageTrackerServiceInterface: adding a method to a public interface breaks every class that implements it.
Consequences
The reader returns installation-wide figures when no user is given. Whether the viewer may see them is the caller's decision: the overviews show them to administrators and give editors their own figures only.
Per-operation counts end where telemetry ends. A period that starts before TelemetryCoverage::$oldestCallAt is incomplete, and a caller says so rather than presenting the sum as the whole.
No breakdown by user name: the per-user table stays in the administrator-only Analytics module.