inference
An inference record describes one model call: which model served it, with which parameters, how many tokens it used, what it cost and how long it took. Records produced by the call point to it with the envelope field inferenceId.
ASR-300 An
inference record MUST contain inferenceId.
ASR-301 A producer MUST write an inference record only when the source identifies a model call (by an ID, a call record, or a usage report attributed to one call). It MUST NOT synthesize model calls from message boundaries. A converter for a source without call boundaries omits inference records and declares the loss inference (ASR-157).
ASR-302 One inference record describes exactly one model call. When the source reports usage only for several calls together (per turn, per session), the producer MUST record it in a usage_summary with callCount if known, and MUST NOT present it as one inference.
A source may identify calls and models without recording usage or cost. An inference without usage is valid. The usage profile requires usage to be recorded when the source has it.
ASR-303 model.id MUST be the model that served the call as the source reports it, and model.requested the requested model or alias as the source reports it. A producer MUST NOT copy one into the other, and MUST NOT infer either from prices, names or other calls, except as ASR-325 allows.
ASR-325 When the source records no model for each call but records the configuration in force for the turn (Codex records the model in each turn’s configuration and not on its usage records), a producer MAY set model.requested from that configuration under a rule in the agent’s registry entry. It MUST then set model.requestedSource to turn_config, and MUST NOT set model.id this way.
params.serviceTier is the provider’s service tier for the call, as the source names it (Claude Code service_tier, Codex service_tier).
ASR-329 attempt.n MUST be an integer of at least 1, and attempt.of, when present, an integer not less than n. Attempt values MUST come from the source.
Usage
Providers disagree on whether input counts include cached tokens. ASR does not pick a convention; it records which one applies.
Anthropic prices cache writes by how long the entry lives. Claude Code and OpenClaw record the split:
inference.usage MUST be the usage of that one call (a delta). Cumulative values belong only in usage_summary with cumulative: true.
ASR-305 Token counts MUST be non-negative integers.
ASR-306 A producer MUST use input.uncached only when the source’s inclusion rule is unambiguous (for example a provider that reports uncached input separately from cache reads and writes). Otherwise it MUST record input.total with input.includesCache.
ASR-307 When input.total is present, input.includesCache MUST be present.
ASR-308 When input.includesCache is true and input.total, input.uncached, input.cacheRead and input.cacheWrite are all present, input.total MUST equal the sum of the other three. When it is false and input.total and input.uncached are present, they MUST be equal.
ASR-309 When output.total and output.reasoning are both present, output.reasoning MUST NOT exceed output.total.
ASR-310 Usage values MUST come from the source. A producer MUST write 0 only when the source reports zero, and MAY add fields only by exact arithmetic on values the source reports under a documented inclusion rule. A schema default or placeholder zero is not a reported value.
ASR-311 Producers MUST follow a documented accounting-selection policy for each source format and backend. Repeated reports for one call are counted once. Reports without a qualified join remain native evidence and MUST NOT be attached by position or counted twice. Declare incomplete coverage when selection omits semantic usage. Message-attributed totals use usage_summary covering that message. The policy states cache and reasoning inclusion rules; it does not invent a call identity.
ASR-326 Producers MUST preserve reported input.cacheWrite and input.cacheWriteByTtl without adjustment. When the TTL values add up to more than cacheWrite, validators MUST warn for every stream. Consumers MUST NOT derive either value from the other. Producer fixtures based on source data check that reported values were kept and that producer arithmetic follows ASR-310; the numbers alone do not show who computed them.
Cost
ASR-312 A
cost MUST contain amount and currency. currency MUST match ^[A-Z]{3}$ or begin with _.
ASR-313 An absent cost means unknown. A producer MUST NOT write 0 for an unknown cost, and MUST NOT label an estimate as provider_reported.
ASR-314 A converter_estimated cost SHOULD carry pricingVersion.
ASR-327 cost.billing MUST come from what the source records for the call or the session. A producer MUST NOT derive it from the account type, the authentication method or the absence of a cost.
Processing inherited context (a forked or continued session sending its inherited history to the model again) incurs new charges. These are the child session’s own costs, separate from the parent’s accounting that was copied along with the history (see Lineage).
usage_summary
A usage_summary records an aggregate that the source reports: a turn total, a running session total, a total over a session and its subagents, or context-window usage.
ASR-315 A
usage_summary MUST contain scope, cumulative and includesChildren, and at least one of usage, cost, byModel, callCount, contextWindow or quota.
ASR-316 When scope is tree, coverage MUST be complete or partial and includesChildren MUST be true. An aggregate whose coverage is unknown MUST NOT claim tree; it is recorded as session with includesChildren: null.
ASR-317 Each byModel entry MUST contain model.
ASR-318 contextWindow.used, contextWindow.size and quota MUST NOT be read or written as token consumption.
ASR-328 Each entry of quota.windows MUST contain usedPercent, a number from 0 to 100.
Counting rules
ASR-319 A cumulative summary replaces earlier cumulative summaries of the same scope andcounter (or, when counter is absent, of the same scope). Consumers MUST NOT add cumulative summaries together.
ASR-320 Consumers MAY add non-cumulative summaries only when they have the same scope and their covered intervals do not overlap.
ASR-334 After applying revisions, a stream MUST contain at most one effective non-cumulative turn summary per turnId and counter (summaries without counter share one scope). Producers MUST aggregate only components known not to overlap, preserve partial coverage and keep the source components at the registry destination. covers.turnId and the envelope turnId, when both present, MUST agree. Sub-turn intervals are not represented by covers.
ASR-321 For any total, consumers MUST use either a covering aggregate or its components (the inference records, turn summaries or child sessions it covers), never both.
ASR-322 Consumers MUST NOT add a parent’s total to a child’s total unless the parent’s summary declares includesChildren: false. A missing child total is unknown, not zero.
ASR-323 Producers MUST NOT copy session or turn aggregates down onto inference records, or divide them across calls.
Design note. The common failure in usage analytics is double counting: counting usage repeated on every line of a split response, summing cumulative counters as if they were deltas, and adding parent totals that already include children to the children’s totals. The rules above make each of these a checkable error.
Request context
inference.context records what one request contained, when the source recorded it, by reference only. Claude Code stores each request as the previous request’s first messages plus new messages, with every message kept once as a content-addressed blob. context.prefixFrom follows the same pattern, so that a stream does not grow with the square of the session length.
In the example session, the first call’s request held the system layer and the user’s prompt. The second call’s request was the first call’s entry followed by the model’s tool call and its result:
context of inference record r4 (inf_01B), the second that of r7 (inf_01C). A source that keeps request messages as content-addressed blobs (Claude Code’s request records) uses {"blob": <BlobRef>} entries instead of refs.
The unit of
count is one entry. The expanded entry list of a context is computed as follows: if it has prefixFrom, take the first count entries of the expanded entry list of the named call’s context; then append the context’s own entries, in order. prefixFrom.inferenceId names the latest revision, with a lower seq than the record that names it, of the inference entity with that ID. Every step of a prefix chain goes to a lower seq, so a chain cannot loop.
ASR-324 inference.context MUST hold references only. It MUST NOT duplicate the text of records it references.
ASR-330 Each entry of context.entries MUST contain exactly one of ref (a ref, ASR-062) or blob (a BlobRef). prefixFrom, when present, MUST contain inferenceId and an integer count.
ASR-331 prefixFrom.inferenceId MUST name an inference record with a lower seq that has a context, and count MUST NOT exceed the length of that context’s expanded entry list.
ASR-332 Readers MUST compute the expanded entry list as defined above.
ASR-333 Readers MUST NOT present a request as exact unless complete is true on its context and on every context in its prefix chain, every prefix in the chain resolves, every ref resolves, and every blob is available (ASR-028). A missing prefix or blob makes the request incomplete, not empty. Producers MUST set complete: true only when the source records the whole request.
The context view (see Structure) is a projection of the recorded evidence; inference.context, where present, is the source’s own statement of what a request contained.