Repository navigation
Align Item, event, reasoning and usage serialization - #77
Merged
Merged
Conversation
Official responses always carry these fields (EVT-09, SES-23, SES-25, VA-11): Item events carry output_index, null for input Items; messages carry phase, null for user messages and when the harness reports none; function results carry output and error, null when not submitted; Agent and Session responses carry reasoning.effort and reasoning.summary, null when unset. No model-derived default effort is filled in. These are wire-only. Stored Item payloads keep their original encoding through Item.MarshalStored, so replayed child Items still compare equal, and stored configuration keeps omitting unset reasoning keys, so creation retry identity is unchanged. The OpenAPI marks phase and output_index nullable. The TypeScript client accepts output_index and phase null and still accepts older Cores that omit them; Core Web accepts a null message phase. The pinned SDK scripts now expect the explicit nulls.
Official streams add an assistant message in progress with empty content, then an empty content part, deltas, output_text.done, content_part.done and item.done, and stream structured output the same way (EVT-10). Core no longer pre-fills the part in item.added. A message first observed complete, such as Claude structured output or a legacy final answer, now follows the same sequence with its unchanged text in exactly one delta; this frames the text and never alters it. Stored Items and reads are unchanged.
Official Session usage stayed null after a root Turn ended with unknown usage (EVT-13), and in three more samples while a root Turn was in progress or waiting, even after earlier Turns were measured (ST-03). Session usage is now the sum of recorded root Turn usage only when every root Turn has ended with known usage, and null otherwise. Queued Turns count as not ended; no official read sampled one. A snapshot an active Turn records stays on that Turn.
A cancelled Codex Turn read all-zero usage where official keeps it null (EVT-24). Native reports a cumulative thread total and the adapter publishes its difference from the Turn's baseline. After an interrupt before any response reported usage, native sent a total that had not advanced, and the adapter published the all-zero difference as a complete measurement, which the cancellation outcome repeated. Core and storage only stored it. The adapter now ignores a total that has not advanced past the Turn's baseline. A later advanced total is still published, and an explicit native zero in a per-Turn usage payload is still kept.
Add the dated item serialization section (S1-S8) with its official evidence (EVT-09, EVT-10, EVT-13, SES-23, SES-25, VA-11, ST-03) and the EVT-24 finding, register SR in the operation evidence with updated rows 7, 12 and 15, and update the execution tools matrix, the deferral notes, the Session usage and runtime history token descriptions and the contributor rules for wire nulls, message framing and usage.
Public Session usage now stays null while a root Turn runs and after an unmeasured Turn. Runtime observation telemetry, history token points and their OTLP export are Core extensions and should not lose that signal. Add a separate tenant-scoped internal query with the previous rule: the sum of every recorded root Turn snapshot, active Turns included, null only when nothing is recorded. The Runtime observation resolver reads it instead of the public value. Session retrieve, list, update and every Session event snapshot keep the public rule.
The live trend reads public Session usage, which is now null while a root Turn runs. Keep a listed Session's last reported totals instead of dropping it, so the series neither falls to zero nor breaks; usage measured meanwhile appears in the interval where it is reported again. Durable history is limited to hosted Sessions, so the live trend keeps its source.
Runtime history token points and telemetry count measured usage continuously and differ from public Session usage by design. Record the Core Web live trend behavior and which consumers use which rule.
The Runtime summary's reported token total summed public Session usage, so it dropped while a Turn withheld usage. Share the live trend's hold as holdLastReported: the summary keeps each listed Session's last reported total across snapshots, a newly reported value replaces it, and unlisted Sessions drop out. Rows still show the current public value.
The live trend re-stamped a held Session total with each sample time, so a running Turn read as 0/min and its whole consumption landed as one spike. Held totals now keep their report time and are marked held; tokenRate treats them as unknown, so those intervals are gaps, never zero. The next reported total is spread over the time since the last report. The Runtime summary keeps its held total.
The resolver and the OTLP token gauges read MeasuredSessionUsage, sqlc also adds SessionMeasuredTokenUsage, and held live-trend intervals are gaps. Note that a root Turn cancelled while queued leaves public Session usage null, an inference with no official sample in ST-03.
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.
Items, events, reasoning and usage now carry the official field presence and sequencing where the pinned types define them. Model output text is never altered and no model-derived defaults or counters are invented. The pinned baseline is unchanged (SDK 3.13.0 / d7c41ef /
agents=v1).Behavior
Null field presence (S1–S3):
item.added/item.donecarryoutput_index: nullwhen there is no index.phase: null for user messages, the native value or null for assistant messages.function_call_outputalways carrieserror(null when none) andoutput.These are applied at rendering. Stored Item payloads keep their previous encoding (
Item.MarshalStored), so replayed child Items and creation-retry hashes are unchanged.Assistant message framing (S4/S5):
item.addedisin_progresswithcontent: [], thencontent_part.addedwith text "", then deltas,output_text.done,content_part.doneanditem.done.Reasoning (S6): Session and saved Agent responses serialize
{effort, summary}with explicit nulls instead of{}. No model default is filled in (official reports model-specific values; that remains a documented difference).Session usage (S7): public
usageis the sum of root-Turn usage only when every root Turn has ended with recorded usage. Otherwise it is null, including while any root Turn is queued, running or waiting. This follows EVT-13 and the scan-5 ST-03 official samples.Core observability is unaffected by S7:
Cancelled Codex Turns (S8):
Client and Core Web: accept the new nulls and still accept older Cores that omit them.
Evidence
Recorded in
history-events-usage.md,execution-tools.md,runtime-history-api.mdandoperation-evidence.md(register SR, rows 7, 12, 15).Validation
Live acceptance: real Core, the daemon and native harnesses on
environment: none. Every image, the Claude bridge included, was built from each tree. 5 Turns per phase. All events and reads were validated with the pinned SDK's strict parse.output_index: nullphasepresenterror/outputpresentCleanup and secret scans passed.
Tests:
-race, including a reproduction of the zero-usage cancel.Server gate on this head: all
make checktargets plus Web typecheck, core-doctor, unit tests and build pass. The Playwright browser cases were not run on the server (no Google Chrome; the user approved the skip).make openapiandmake sqlc-generateare byte-identical.Independent blind review by a fresh Claude Code subagent (the user-approved replacement for GPT-6 Astra). It found no blockers and confirmed in code: stored Item payloads and creation-retry hashes are unchanged; the Claude structured-output path produces exactly one byte-identical delta; S7 counts only root Turns; every public caller uses the public rule; and the telemetry query is tenant-scoped. Its follow-ups are fixed in the last two commits:
These were verified by Web tests and the gate on the final head, without a new review, per the user's rule.
No full protocol compatibility is claimed.
Need help on this PR? Tag
@codesmithwith what you need. Autofix is disabled.