Repository navigation
feat(telemetry): measure codex from its own session files - #1057
Merged
Merged
Conversation
The block reader, the listing and the open-stat-read skeleton move out of the Claude Code source into a module every source shares. A source may hand lines before the saved offset as not counted, and the read use case makes its format once per file read, so a format can hold what earlier lines said. Claude Code reads exactly as before. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
A reader of Codex's rollout files joins the ingest list. Only a token_usage_record line is a call; its model and directory come from the latest turn_context before it, its version and branch from the file's first session_meta, so a file that moved is read from its start and the lines before the saved offset only build that context. Compressed files are read whole, once, as a stream; a Node without zstd names each one. Every sandbox that runs the CLI now relocates CODEX_HOME. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
Kills the mutants the changed-line run left alive in the Codex reader: the rollout name pattern's anchors and wildcard, the oldest-written time of its files, and a session_meta read after a turn_context. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
…mits The usage contract gains Codex's files, its line-to-record table and its residual limits, among them a thread resumed from a history with no per-call records. The plugin README, the envelope reference and both memory banks stop saying Claude Code only. The task folder holds the contract, the plan and the evidence, the real-corpus reconciliation included. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
The telemetry command's description said it measures Claude Code sessions only. The plugin README now says why a Codex call takes its task from its branch alone: the plugin's hooks run in Claude Code. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
A .jsonl.zst whose stream zlib cannot decompress failed every ingest and report, for both tools, and the session-start hook hid it. It is now one unrecognised shape naming zlib's code; the file keeps its position and is tried again by the next run. An I/O error still fails the read. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
The memory bank said the sandbox guard holds the CODEX_HOME relocation; it did not. It now does, even when the runner sets its own CODEX_HOME. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
A truncated frame is named Z_BUF_ERROR, not ZSTD_error_*: the test holds both prefixes of what is passed over. The code is read with String() rather than a fallback no error reaches. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
The consent explanation shown before opting in, the stop and answer steps, the plugin and marketplace descriptions, the README, the architecture, FAQ and catalog pages said Claude Code only. The retention hint now says a tool may have removed older session files. The usage contract states what a .jsonl.zst's offset is and what a file turning compressed counts again, and the evidence records review round 1. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
blafourcade
force-pushed
the
feat/telemetry-codex
branch
from
October 19, 2026 07:20
a42c202 to
b79fcdf
Compare
Node 22's zlib ends a cut zstd frame with no error and short output, so a truncated .jsonl.zst was read as complete, its position saved and its missing calls lost. The reader now counts the decompressed bytes against the content size the frame header declares; another size is one unrecognised shape, and the file keeps its position to be read again. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
Kills the mutants the changed-line run left in the frame header reader: a single segment's width read from the flag, a frame declaring no size, the shortest header holding one, and a stream left unchecked when its frame declares nothing. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
Per-call records ship from Codex 0.153, earlier sessions count nothing; the calls Codex writes no record for, the cost fields its file lacks, cache writes as OpenAI bills them, frames without a size before 0.152, coexisting plain and compressed copies, and forks. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw
blafourcade
marked this pull request as ready for review
October 19, 2026 09:29
This was referenced Oct 19, 2026
Merged
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.
🎯 What & why
A person who works with Codex in a clone that opted in now sees that work in
aidd telemetry report. Until now only Claude Code was read. The decision, the mapping and the properties are in contract.md, and the measurements are in evidence.md.🛠️ How it works
token_usage_recordline is a call. Its usage is read, never the running totals beside it.turn_context. Version and branch come from the file's firstsession_meta.CODEX_HOME, else~/.codex, undersessions/andarchived_sessions/..jsonlthat moved is read from byte 0. Lines before the saved offset are handed on as not counted..jsonl.zstis decompressed as a stream, once. Its decompressed bytes are counted against the size its frame header declares, because Node 22's zlib ends a cut frame quietly, short (zstd-frame.ts). One that does not decompress, or decompresses to another size, is one unrecognised shape naming why: it keeps its position, is tried again next run, and stops no other measurement. An I/O error still fails the read.0x0aonly). Claude Code reads exactly as before, and its adapter tests are unchanged.CODEX_HOME:tests/e2e/helpers.ts, the telemetry sandbox, and both Claude end-to-end scripts.🧪 How to verify
cd cli && pnpm testnpx vitest run tests/contexts/telemetry/application/codex-transcript-ingest.property.integration.test.ts: P1 (any split of a file's growth stores the same ledger, and the runs' counts add up) and P3 (plain, then compressed, each call stored once).pnpm testpasses on Node 22.18.0 and 24.20.0 (6851 tests each)..jsonl.zstin a clone that opted in, thenreport --jsontwice. Both exit 0 withunrecognised_shapes1..jsonl.zstthat does not decompress is tried again every run: calls decoded before the bad frame are stored once, but that run's figures count them again each time. Written as a limit..jsonl.zst, the saved offset is the file's compressed size. The file is read once, and its size and identity keep it read.offsets.jsonkeeps its format; the contract and the usage contract now say what the offset means for these files. An unterminated last line in one is never read.run.oldest_transcript_atis the oldest file across both tools. Codex's archive can be older than Claude Code's retention, and that is what the field states..zstimport zlib as a namespace and skip when zstd is absent, so they load on Node 22.12 to 22.14.git_branchis the branch the session started oninput_tokens, billed only on GPT-5.6 and later; a negative input was never seenresponse_id, so they are stored once.zstwhose frame declares no size is read unchecked, and of a file of several frames zlib reads the first alone.zstthat does not decompress is retried, its decoded calls counted again in each run's figures.jsonlturning into a.jsonl.zstcounts that run's unrecognised shapes and not-stored calls againmutation-covers-source.arch.test.tsonce timed out at 6 s against the 5 s default, during a pre-commit while the scripts suite ran beside it. It passed alone and on the retry.🔗 Linked issue
None. Found by the release 2 scope: Codex is measured.
✅ I certify
🤖 Generated with Claude Code
https://claude.ai/code/session_01TnCgcujM2xi6T6dkmVogVw