# Proof audit pass 1

Target: [#24157](https://github.com/pingdotgg/t3code/pull/24157), [GitCafe #24157](https://git.cafe/pingdotgg/t3code/pulls/24157), issue [#24136](https://github.com/pingdotgg/t3code/issues/24136).

Reviewed full local diff: base [fef851bee0](https://github.com/pingdotgg/t3code/commit/fef851bee09102641061aeb78a3092c2ba2c72ab) to candidate [19235a6884](https://github.com/pingdotgg/t3code/commit/19235a6884520b5ed2b6dfdaf0ed7e03dee5d5f0), eight files, 277 insertions/9 deletions. Clean checkout when inspected. GitCafe still reports published head [dfedee32e2](https://github.com/pingdotgg/t3code/commit/dfedee32e24290bcf025ada7c7baa23be84ab0d5); its ten successful checks do not validate this local candidate. No edits to repository, capture, browser, dev server, push, review/comment, or merge performed.

## Capture matrix

Empty (0 rows). Server behavior and protocol fix; no renderer/layout/assets changed. Existing unread presentation consumes the resulting timestamp. Screenshots cannot establish own-agent identity, scheduler delivery, deferred timing, or persistence. Proof is a red behavior test plus runtime transcript.

## Fixture/proof matrix

| Row | Trigger / fixture | Required observable behavior | Evidence at pass 1 |
| --- | --- | --- | --- |
| 1 | Own agent; previous completed seed; settled thread; actual interval scheduler starts next run; mark_unread while running | Tool accepts with marksUnreadWhenTurnEnds=true; timestamp unchanged until completion; persisted timestamp becomes that run completedAt minus 1 ms | Main runtime reproduction proves rejection; candidate real-handler test passes, but actual candidate scheduler/provider transcript missing |
| 2 | Own agent with omitted threadId | Caller resolves to current thread and follows deferred path | Candidate handler regression test uses omitted threadId; passes |
| 3 | Own agent with explicit matching threadId | Same deferred success | Main reproduction uses explicit ID; after transcript must retain it |
| 4 | Deferred target completes successfully | thread.marked-unread after terminal run; correct runId; exact lastVisitedAt | Candidate integration test checks event and exact timestamp; pass |
| 5 | Deferred target fails / is interrupted | No mark-unread dispatch; visit state preserved | Service status table covers both (dispatch observation, mocked orchestrator) |
| 6 | Newer run is queued/running/completed when old deferred command lands | Old runId cannot mark the newer run unread; preserve current lastVisitedAt | Guard exists in Orchestrator; no dedicated newer-run assertion in full diff |
| 7 | Visit at or after completion arrives before deferred command | Preserve visit, including equality boundary | Integration test covers completedAt + 500 ms; equality not exercised |
| 8 | Visit arrives after deferred command | Ordinary visit restores read state | Existing visit path unchanged; not explicitly asserted by new test |
| 9 | Another agent / client, or own agent without active run | Immediate command behavior retained; completed latest run succeeds; active/no completed latest run still rejects | Source trace only; existing runtime mark-unread test covers completed thread |
| 10 | Wait timeout / restart continuation / shutdown | Timeout does not mark active run; continuation follows existing waitForThread; in-memory wait lost on restart | timedOut guard and reused waitForThread traced; no new dedicated timeout/restart proof |
| 11 | Ordinary settle, other organize actions | Existing dispatch/result behavior unchanged | Shared timeout constant renamed only; settle implementation unchanged; no broader test run in this audit |
| 12 | Command serialization / relay / projections | Optional runId backwards-compatible; deferred mark flows through existing event/shell/read-state paths | Contract and projection callers traced; relay test mock adds service methods only |

## Complete changed-file coverage

- apps/server/src/mcp/toolkits/thread/handlers.ts: only mark_unread now calls service; byOwnAgent compares caller and target IDs; access wrapper retained.
- apps/server/src/mcp/toolkits/thread/tools.ts: deferred result union and description; no visual component.
- apps/server/src/orchestration-v2/ThreadManagementService.ts: own-active deferral, layer-scoped fiber, successful terminal gating, run-scoped command; shared wait constant.
- apps/server/src/orchestration-v2/Orchestrator.ts: atomic latest-run and visit ordering guards; immediate command remains strict.
- packages/contracts/src/orchestrationV2.ts: optional runId added (the original published PR description's “no contract changes” no longer describes the local candidate).
- apps/server/src/orchestration-v2/runtimeLayer.test.ts: real MCP handler; synthetic message.dispatch and eventSink completion; exact timestamp and newer visit assertion. This fixture is not an actual scheduler/provider run and never settles the fixture thread.
- apps/server/src/orchestration-v2/ThreadManagementService.test.ts: completed/failed/interrupted status table.
- apps/server/src/relay/AgentAwarenessRelay.test.ts: service mock shape only.

## Affected callers and surfaces

MCP t3_thread_organize is shared by manual and scheduled provider turns. Codex, Claude, Cursor, Grok, OpenCode and Antigravity use the same server service/handler once MCP invocation context is present; no adapter changes. Codex is the real runtime reproduction provider; Claude was the issue reporter's provider. No evidence supports claiming all providers were executed.

Other-agent targets and external/client calls retain immediate behavior. Shared client-runtime operations/commands.ts markThreadUnread dispatches without runId through state/threadCommands.ts. Web useThreadActions/useThreadActionMenu and current/legacy sidebar context/bulk actions use this existing path; desktop wraps web, including its context menu. Settings and composer have no newly changed entry point. No new keybinding was introduced. Mobile has no markThreadUnread action found in its source; it consumes lastVisitedAt through threadListV2 and ThreadDetailScreen visit tracking. Reverse action remains thread.visit.

Event path: orchestrator thread.marked-unread -> ProjectionStore / shell publication and AgentAwarenessRelay -> client-runtime orchestrationV2Projection/read state -> existing web Sidebar/LegacySidebar status and mobile threadListV2 unread calculations. Local/remote/relay/tunnel share the server command and timestamp; no origin or transport changes. No client-specific captures required. No docs changes needed for a changed UI workflow; tool description is updated.

## Existing main proof and red-test provenance

Read /tmp/issue-24136-repro/REPORT.md, tool-transcript.log, schedule/setup/evidence scripts and related projections. Main SHA matches base. Real Codex gpt-6.1-sol seed ordinal 1 completed; interval everyMs=60000 created; thread.settle committed; actual scheduled message starts ordinal 2. Persisted t3_thread_read shows ordinal 2 running, activeRunId, completedAt=null and earlier completed ordinal 1. Persisted t3_thread_organize on the same explicit thread returns OrchestratorMcpFailure orchestration_error “has no completed run to mark unread.” Run 2 subsequently completes. The external RPC mark-unread succeeds only after completion; that control is not an after-fix reproduction.

Red test commit [7e25929a8f](https://github.com/pingdotgg/t3code/commit/7e25929a8fb83d3596930e96deed99c53fcfdd03) has base as direct parent and adds the handler fixture before implementation is merged. It asserts against actual returned tool failure, not a missing method. Stored source and history confirm test-first ordering. User reports red failure and candidate pass; no separate saved red-run output was present in the supplied reproduction directory, so retain the original red command/output in final proof. Audit independently ran the candidate handler test: 1 passed, 86 skipped. No red checkout/source mutation performed in this read-only audit.

## Minimum candidate runtime transcript assertions (required)

1. Record exact candidate SHA, isolated T3 home, provider/model, transport/protocol, start/stop ownership. Never publish auth material or pairing URLs.
2. Use the same actual interval scheduler and real provider as main proof: completed seed, bound interval task, explicit successful thread.settle and projection settledOverride=settled/settledAt before trigger. Show scheduled task ID/message provenance and next run ordinal. A manual message or runNow is not equivalent.
3. During the scheduled provider turn, persist t3_thread_read output proving current run active/running, completedAt=null, prior seed completed, matching thread ID. Show the provider's actual t3_thread_organize input {threadId,action:mark_unread}; no external RPC substitution.
4. Persist full tool output via getTurnItem: success, marksUnreadWhenTurnEnds=true, no orchestration_error. Demonstrate response happened before that run completed. Record lastVisitedAt immediately before and after acceptance while still active: no early rewind/event attributable to the mark.
5. Await actual successful provider completion for the same run (no injected completion). Observe persisted thread.marked-unread after completion, and final projection lastVisitedAt exactly completedAt minus 1 ms. Correlate thread/run/command/event sequence; ensure no newer run/visit confounds the positive case.
6. Do not issue the post-completion external mark-unread control before final assertion: that would mask a broken deferral. Disable the interval after the first candidate firing; record cleanup. A success acknowledgement alone is insufficient, as is an eventual timestamp without proof it was produced by deferral.

The real after transcript is required for row 1. For the added race behavior, deterministic event-based tests are the appropriate proof: retain newer-visit test and add/provide a newer queued/active/completed-run guard fixture. They need not be separate expensive provider runs. Equality boundary is useful focused coverage, not a separate UI capture.

## FRICTION

Published PR head and local candidate differ; published CI/bot approvals apply to the former. Existing main helper had protocol v2 vs 2 and unsupported creationSource=user, corrected and recorded in original report. The candidate “scheduled run” test is synthetic, so its name must not be mistaken for scheduler/provider proof. No raw configuration/provider logs uploaded: only this hand-written, secret-free matrix. Missing candidate runtime proof is intentional pass-1 incompleteness, not a code verdict.

VERDICT: INSUFFICIENT — missing same-flow candidate scheduler/provider settled-thread transcript with deferred success and exact eventual timestamp; no saved red-run output supplied for independent verification; newer-run ordering guard lacks a dedicated fixture in the complete diff.
