Usage-block normalisation across the OpenAI-compatible dialect variants.
Purpose
-------
:func:`normalise_usage` folds the ``usage`` block every lane returns into
one :class:`UsageStats`. The lanes all claim the OpenAI chat-completions
dialect, but they differ in which optional sub-blocks they populate:
Groq and Cerebras report ``completion_tokens_details.reasoning_tokens``;
OpenRouter adds a top-level ``cost`` (USD, ignored here — pricing is
``oc_pricing``'s job) and may report ``prompt_tokens_details``; Bitdeer
and NVIDIA NIM report neither and leave the optional blocks absent.
Responsibilities
----------------
- :func:`normalise_usage` — total, defensive dict → :class:`UsageStats`.
- :func:`_as_dict` — coerce a pydantic sub-block (or anything else) to a
plain dict so ``isinstance(x, dict)`` checks in callers hold.
- :func:`_as_int` — coerce a reported count to a non-negative int.
Diagnostics
-----------
Domain: OC_CHAT.CLIENT
Levels:
L2 — lifecycle events
L3 — semantic details
L4 — deep tracing
Contracts
---------
- Total: any input — ``None``, a non-dict, a partial block, a block with
string counts — yields a :class:`UsageStats` rather than raising. A
usage block is telemetry; a malformed one must never abort a turn.
- Absent fields normalise to 0, which callers read as "no data" (the
contract's own zero-hit-zero-miss convention).
- ``total_tokens`` is derived as prompt+completion ONLY when the lane did
not report it; a reported total is never overwritten.
- ``cache_hit_tokens`` comes from ``prompt_tokens_details.cached_tokens``
(the OpenAI-standard prefix-cache field). The miss side is the reported
prompt total minus the hit, floored at 0 — never negative on a lane
that reports a cached count larger than its own prompt count.
- Money is NOT parsed here. ``usage.cost`` (OpenRouter/Vercel) is
deliberately dropped: plan 202's fail-closed pricing path owns cost,
and a provider-asserted figure entering by this door would bypass it.
Dependencies
------------
- oc_diagnostics (structured debug logging via _dbg)
- option_c_agent_contracts (UsageStats)