# Issue 23919 — read-only proof audit, pass 1

Scope: complete diff a46f80ee28..d416a4ec6e, fix/issue-23919. Audited source and supplied before evidence only. No app execution, capture, tests, edits to worktree, forge writes, or delegation. Existing 81 passing tests are reported by lead, not rerun here. No after proof yet: proof gate remains open.

## Why real-app evidence applies

Only CodexAdapterV2.ts and CodexAdapterV2.test.ts change, but their output directly controls timeline runs, messages, tools, pending requests, and completion. This is not a server-only exception. The new map holds unknown root-native turns, offers a provider continuation on user-message/end, registers a T3 run through startTurn adoption, and replays held notifications/requests without issuing another native turn/start. One live web client against the isolated server is sufficient representative rendering proof; desktop shares web and mobile consumes the same unchanged contracts. No per-provider, viewport, connection-mode, settings, palette, or theme Cartesian matrix is justified.

## Existing before proof

[Native transcript](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/a773bb5854ad6df7/before-runtime.txt): baseline a46f80ee28, Codex 0.163.0, READY completed; external queue accepted; native QUEUED user item/reply/completion observed; UI still READY only afterward.

![Before: READY remains alone after native QUEUED completion](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/6c3d08f453a38414/browser-screenshot-localhost-mvmdxfws-3d4dc630.png)

This supports the original missing-turn defect. A still cannot prove temporal transitions, request submission, or absence of duplicate native execution. Do not recapture baseline unless correlation or fixture equivalence is disputed.

## Fixture matrix (minimum scoped proof)

| ID / priority | Seed and trigger | Visible acceptance + runtime corroboration | Evidence |
|---|---|---|---|
| A / required root regression | Live-loaded, idle, unarchived Codex root thread with completed READY and no active goal. Externally run `codex queue --thread <native-id> --message "Reply with the word QUEUED."`. | A single new T3 run owns the original native turn; initiating notification and QUEUED answer appear once in correct order after READY; run settles. Persisted message retains exact queued prompt; initiating row may be notification rather than user bubble. Native trace shows one queued turn and no extra T3-issued native turn/start for adoption. | RECORDING: READY → external queue → visible completion. Final after still at comparable 1280×800 scale plus sanitized ID-correlated runtime excerpt. Existing before pair suffices. |
| B / required tool propagation | On the same now-idle loaded thread, queue a prompt that explicitly runs a harmless shell command producing unique marker TOOL_23919, then answers DONE_TOOL_23919. | Adopted run shows command item, output marker (expand tool detail if folded), and final reply; command completion precedes settled answer. No orphan or duplicated tool/run. | RECORDING: queue → tool lifecycle/detail expansion → final answer. Can combine with C in one turn/clip. |
| C / required request round trip | Configure a disposable test thread to reliably require a command approval, then externally queue a harmless command prompt; use actual approval policy supported by installed Codex. Do not use the full-access READY thread and expect approval. Alternatively/also use plan mode with explicit request_user_input where available. | Pending request belongs to adopted run in selected thread; T3 can submit decision/answer; native request receives response; execution resumes; pending panel clears and run settles. At least one real server-request round trip required, not just a card still. Approval is deterministic preferred minimum; user input adds distinct request family if change claims that flow. | RECORDING REQUIRED: pending → respond → cleared → reply. Capture sanitized native request ID/T3 request/run linkage. A prompt that never emits a request is inconclusive, not a pass. |
| D / required follow-up and durability | After A (or combined B/C), send ordinary composer prompt `Reply with the word NEXT.`; after settlement reload/reselect thread. | Exactly one normal NEXT turn and reply; READY and adopted history remain; no phantom running state, duplicated wake, lost tool output, or remaining pending request. Native turn/start occurs for NEXT, unlike adoption. | RECORDING: normal send/completion and reload/reselection; final still can include adopted history and NEXT. No artificial waits needed. |

Minimum capture package: existing baseline transcript + still; one concise after clip for A/D; one tool/request clip for B/C (combine where deterministic); one or two after stills; a small sanitized runtime/projection excerpt linking native turn IDs to T3 run/message/request IDs. Do not require separate baseline tool/request demonstrations: the root native turn is absent on baseline and the provided evidence already establishes that defect. New after clips establish the broader wrapper paths actually work.

## Source/test-only branches, not extra mandatory UI fixtures

- Promptless end fallback: offerExternalTurnWake derives message ID from turn ID and null detail at end if no user item appeared. No ordinary CLI reproduction established; use focused adapter coverage if supported/claimed. Do not invent a real queue scenario to force it.
- Held-frame timing: transcript replay covers completion before adoption and subsequent normal start; real A validates continuation service integration absent from adapter harness. Request buffering before adoption is a distinct unproven ordering path; focused deterministic replay is better than timing-sensitive browser attempts.
- Repeated external turns: reuse B/C after A gives a modest second adoption check without a dedicated stress suite.
- Existing active/pending root turns, native subagents, goal-held turns, and goal stop retain earlier dispatch branches; use existing focused regressions, not new live UI combinations. Non-Codex providers are unchanged.
- Error/failed or cancelled external turns use newly wrapped notifications and are useful targeted adapter tests if absent; not a prerequisite for a minimal happy-path UI before/after package. Avoid claiming all request families or all terminal states from one live run.

## Seed and execution path for lead (not executed by auditor)

Lead reports isolated worktree `.t3` with one READY thread and no running server. A stored READY thread alone does not establish the adapter rootProviderThreads map: start the isolated dev server normally, select it, and establish a live loaded Codex session. If history selection does not load the native thread, send a small normal READY prompt and await actual completion. Read current native thread ID from this environment's provider-thread projection/runtime trace; never infer it from T3 thread ID or reuse baseline ID. Keep session loaded through external queue; do not restart server between load and trigger.

Use the real composer for seeding and NEXT. An authenticated isolated-environment RPC can call the same thread startTurn/message.dispatch path to seed normal READY and inspect projections; use current contracts/client command implementations rather than guessed endpoint names. The behavior under test MUST enter through external `codex queue` against that native thread, not a T3 queue mutation or synthetic DB insert. Native CLI must address the same Codex home/app-server context as the adapter; accepted queue alone is insufficient without native frames for that exact loaded thread. Obtain CLI syntax from its help if local version differs.

Configure request policy/interaction mode through app or supported RPC before the request fixture. Seed approval on a separate disposable thread if changing READY's policy would disturb comparison. Request replies should be clicked in real app for C, not only sent over RPC. Never write to live userdata; never publish tokens, auth cookies, pairing URLs, or full private prompts in traces.

## Rendering conditions and affected paths

Changed: apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts (heldExternalTurns, wake, wrappers, adoption) and matching test file.

Integration: ProviderContinuationService.ts dispatches message.dispatch with deterministic message ID, original prompt as detail, notification summary `Message queued in Codex`, createdBy agent, creationSource provider, queue_after_active. Orchestrator.ts materializes the notification/run and effect worker calls adapter startTurn. Assert prompt persistence separately from an ordinary user-bubble expectation.

Web: ChatView.tsx uses current server projection and live turn items; session-logic.ts maps notification items to work rows, user/assistant items to message rows; MessagesTimeline.logic.ts groups/folds activity. Expand relevant completed work if necessary instead of declaring hidden tool detail missing. usePendingThreadRequests.ts only derives pending cards when projection.thread.id matches activeThreadId; select correct environment/thread and ensure operate scope allows responding. Normal completed tool output and live request panels require actual provider emissions, not just terminal success.

No renderer, shared wire schema, mobile UI, desktop shell, MCP transport, or alternate entry point changed. Their read-only consideration is sufficient; do not claim they were individually exercised.

## FRICTION category | happened | avoidance

- Evidence fetch | Web fetch returned Internal Error for supplied transcript; direct curl read succeeded. | Fetch public text/artifacts directly when web extraction cannot read them; no browser needed.
- Fixture readiness | Lead has persisted READY data but no server; loaded provider session is not yet demonstrated. | Establish live root session and correlate current native ID before external queue.
- Request determinism | Existing before uses full access; that cannot reliably prove approval handling. | Use supported approval policy in a disposable fixture and confirm native request emission; mark unavailable user-input family explicitly.
- Presentation expectation | Wake is represented as notification, not necessarily queued prompt bubble. | Assert persisted prompt and run linkage separately; inspect actual notification/reply rendering.
- Evidence status | Replay test and reported 81 passes are not integrated real-app after evidence. | Complete A–D with concise recordings before closing proof gate; no exhaustive UI sweep.
