Skip to content

[codex-analytics] replay protocol-native item timing#20239

Closed
rhan-oai wants to merge 2 commits intorhan/app-server-item-timingfrom
pr20239
Closed

[codex-analytics] replay protocol-native item timing#20239
rhan-oai wants to merge 2 commits intorhan/app-server-item-timingfrom
pr20239

Conversation

@rhan-oai
Copy link
Copy Markdown
Collaborator

@rhan-oai rhan-oai commented Apr 29, 2026

Why

Once protocol-native lifecycle timing is available on the public app-server surface, replay consumers need to preserve it instead of rebuilding partial legacy-only events. Keeping that adapter layer separate makes it clear which changes are about consumption rather than production or wire shape.

What changed

  • Carries native timing through the exec JSONL bridge.
  • Replays timestamped app-server items into the TUI legacy event path for command execution, collaboration, web search, image generation, and patch flows.
  • Updates TUI and exec tests so replayed items retain the new lifecycle fields.

Verification

  • cargo test -p codex-exec event_processor_with_json_output
  • cargo test -p codex-tui --no-run

Stack created with Sapling. Best reviewed with ReviewStack.

@rhan-oai rhan-oai force-pushed the pr20239 branch 4 times, most recently from 93b611d to a5f2318 Compare April 29, 2026 18:53
rhan-oai added a commit that referenced this pull request Apr 29, 2026
## Why

Codex analytics needs a typed seam for app-server-originated
request/response traffic so future tool-approval analytics can consume
those facts without adding bespoke callsite tracking each time. Server
responses arrive as JSON-RPC `id + result` payloads, so analytics has to
reconstruct the matching typed response from the original typed request
while that request context still exists in app-server.

This also puts analytics on the app-server outbound path, which needs to
avoid keeping the runtime alive during shutdown. The final ownership fix
keeps the normal strong auth-manager retention in analytics and makes
the external-auth refresh bridge hold a weak back-reference to
`OutgoingMessageSender`, breaking the runtime cycle at the bridge
boundary instead of exposing retention policy through the analytics
client API.

## What changed

- Adds typed `ServerRequest` and `ServerResponse` analytics facts, plus
`AnalyticsEventsClient::track_server_request` and
`track_server_response`.
- Renames the existing client-side facts to `ClientRequest` and
`ClientResponse` so reducers can distinguish client-to-server traffic
from server-to-client traffic.
- Adds `ServerRequest::response_from_result`, allowing a stored typed
request to decode the matching typed server response from a raw JSON-RPC
result payload.
- Threads `AnalyticsEventsClient` through `OutgoingMessageSender` and
records targeted server requests, replayed targeted requests, and
matching targeted responses with the responding connection id needed for
correlation.
- Intentionally leaves broadcast server requests/responses out of
analytics for now because the current model is per connection, while
broadcasts fan one logical request out across multiple connections.
- Breaks the app-server shutdown cycle by storing
`Weak<OutgoingMessageSender>` in `ExternalAuthRefreshBridge` and
upgrading it only when an external-auth refresh is actually requested.
- Keeps reducer ingestion of the new server-side facts as no-ops for
now; this PR is plumbing for later tool-approval analytics work.

## Verification

- `cargo test -p codex-analytics`
- `cargo test -p codex-app-server outgoing_message::tests::`
- Covers typed-response reconstruction plus the targeted, replayed,
broadcast-exclusion, and response-attribution analytics paths.

## Follow-up

This PR intentionally stops at ingestion plumbing, so `ServerRequest`
and `ServerResponse` facts are still reducer no-ops. Once a follow-up PR
adds real downstream analytics output for those facts:

- replace the temporary pre-reducer observation seam with reducer tests
for the emitted event shape;
- add end-to-end coverage in `app-server/tests/suite/v2/analytics.rs`
for the real app-server workflow and captured analytics payload;
- remove the temporary sender-level observer tests added here in favor
of the real-output coverage above.

---

[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/17088).
* #18748
* #18747
* #17090
* #17089
* #20241
* #20239
* __->__ #17088
Base automatically changed from pr17088 to main April 29, 2026 19:56
@rhan-oai rhan-oai force-pushed the pr20239 branch 5 times, most recently from e238b73 to 51e71ee Compare April 29, 2026 22:54
@rhan-oai rhan-oai force-pushed the pr20239 branch 2 times, most recently from 5210475 to d5bedde Compare April 30, 2026 00:08
@rhan-oai rhan-oai force-pushed the pr20239 branch 2 times, most recently from 4dfe7b0 to e256fae Compare April 30, 2026 01:24
@rhan-oai rhan-oai changed the base branch from main to rhan/thread-analytics-state April 30, 2026 01:41
@rhan-oai rhan-oai force-pushed the rhan/thread-analytics-state branch 2 times, most recently from 3fc7386 to d877e6a Compare April 30, 2026 20:58
@rhan-oai rhan-oai force-pushed the pr20239 branch 4 times, most recently from 3ba9aa2 to effe7c6 Compare April 30, 2026 22:28
@rhan-oai rhan-oai changed the title [codex-analytics] add protocol-native item timestamps [codex-analytics] replay protocol-native item timing Apr 30, 2026
@rhan-oai rhan-oai changed the base branch from rhan/thread-analytics-state to rhan/app-server-item-timing April 30, 2026 22:29
@rhan-oai rhan-oai force-pushed the rhan/app-server-item-timing branch from 65ef7bc to 84e66f0 Compare April 30, 2026 22:57
@rhan-oai rhan-oai force-pushed the rhan/app-server-item-timing branch from 84e66f0 to 0cf1a11 Compare April 30, 2026 23:09
@rhan-oai rhan-oai force-pushed the rhan/app-server-item-timing branch from 0cf1a11 to e15f9f5 Compare April 30, 2026 23:32
@rhan-oai rhan-oai force-pushed the rhan/app-server-item-timing branch from e15f9f5 to e77df6b Compare May 1, 2026 00:17
rhan-oai added a commit that referenced this pull request May 1, 2026
## Why

Several analytics event families need the same per-thread attribution
state: the app-server client/runtime associated with a thread and, for
lifecycle-oriented events, the thread metadata captured during
initialization. Keeping connection ids and lifecycle metadata in
separate maps made each consumer rebuild the same thread context and
made subagent attribution harder to resolve consistently.

## What changed

- Replaces the separate thread connection and metadata maps with one
reducer-owned `threads` map.
- Routes guardian, compaction, turn-steer, and turn analytics through
shared thread-state lookups while preserving turn-origin attribution for
turn events and request-origin attribution for steer events.
- Lets newly observed spawned subagent threads inherit their parent
thread connection so later thread-scoped analytics can resolve through
the same state model.
- Adds regression coverage for standalone `SubAgentThreadStarted`
publication plus the `SubAgentSource::ThreadSpawn` parent fallback
through a thread-scoped consumer that depends on inherited connection
state.

## Verification

- `cargo test -p codex-analytics`

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/20300).
* #18748
* #18747
* #17090
* #17089
* #20239
* #20515
* #20514
* __->__ #20300
@rhan-oai rhan-oai force-pushed the rhan/app-server-item-timing branch 3 times, most recently from 087ce59 to a862056 Compare May 1, 2026 04:49
@rhan-oai rhan-oai force-pushed the rhan/app-server-item-timing branch from a862056 to 158fe58 Compare May 1, 2026 06:14
@rhan-oai rhan-oai force-pushed the rhan/app-server-item-timing branch from 158fe58 to 27e04d5 Compare May 1, 2026 15:28
@rhan-oai
Copy link
Copy Markdown
Collaborator Author

rhan-oai commented May 1, 2026

Superseded by the collapsed two-PR timing split; the remaining compile-required changes now live in #20515.

@rhan-oai rhan-oai closed this May 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant