Repository navigation
Description
Before submitting
- I searched existing issues and did not find a duplicate for the hidden PreCompact hook stop reason.
- I included enough detail to investigate the problem.
Area
apps/server
What happened
In T3 Code desktop 0.1.5, a Codex project PreCompact hook intentionally stopped a turn and supplied an actionable stop reason. The provider protocol log contains that reason in hook/completed, but the thread timeline shows only Run interrupted · Stopped by the provider. The user cannot discover from that interruption item which hook stopped the turn or what recovery action it requested.
The local guard's policy also creates a recovery trap: it requires a current checkpoint before compaction, so a turn needing compaction stops before the assistant can save that checkpoint. That policy is custom local code. This report concerns T3 hiding the reason, not a request to bypass the hook or a claim that T3 caused the missing checkpoint.
Steps to reproduce
Observed scenario, not a fresh synthetic host reproduction:
- Configure a trusted synchronous Codex
PreCompactcommand hook. A proposed reduction of the observed custom guard prints{"continue":false,"stopReason":"Save a current task checkpoint before compaction."}; this reduced hook has not been tested in a fresh T3 thread. - Continue a sufficiently long thread until Codex triggers compaction on the next turn.
- Send a normal user message. The hook stops the turn.
- Compare the provider protocol log's
hook/completedevent with the interruption item in the thread.
The custom hook was separately replayed against its real ledger and returned the expected denial. No fresh disposable T3 thread or forced compaction was used during diagnosis.
Expected behavior
Show the hook identity/event and supplied stop reason in the thread when a hook stops a turn. Preserve the intentional stop. A user should be able to distinguish a local policy stop from a provider outage and know the required recovery action.
Actual behavior
The provider log has an actionable kind: stop entry. Codex then emits turn/completed with status: interrupted and error: null. The visible interruption item contains only Stopped by the provider.
T3 would need to associate the earlier hook/completed event with the stopped turn to expose the reason. Codex omitting that reason from its terminal event may also be part of the upstream fix; ownership across the integration is for maintainers to determine.
Inspection of the installed app bundle confirms the interruption-result builder falls back to input.reason ?? "Stopped by the provider".
Impact
Major degradation in the affected existing thread. This report traces one turn end to end; local hook audit records also show earlier CHECKPOINT denials. The UI did not expose the recovery instruction. A separate browser-access blocker remained in the task, so this report does not claim the hook was the sole obstacle to completing it or establish prevalence across installations.
Version or commit
T3 Code desktop 0.1.5 (installed app version and last-started version both checked). The local codex --version reports codex-cli 0.166.0; exact running provider-binary identity has not been independently established. No T3 source patches were made during diagnosis.
Environment
macOS 26.2, T3 Code desktop, Codex provider, an existing long thread, trusted project command hooks.
Logs or stack traces
Minimized protocol fields from one observed turn on 2026-10-29 (UTC); IDs, project paths and task contents omitted:
{"time":"22:56:38.818Z","method":"hook/completed","run":{"eventName":"preCompact","source":"project","status":"stopped","entries":[{"kind":"stop","text":"Agent harness [CHECKPOINT]: Save a current harness checkpoint with decisions, verified state and next action before compaction."}]}}
{"time":"22:56:39.421Z","method":"turn/completed","turn":{"status":"interrupted","error":null,"durationMs":1017}}
{"time":"22:56:39.423Z","type":"run_interrupt_result","status":"interrupted","text":"Stopped by the provider"}Workaround
Save a truthful current checkpoint for the affected local task outside the stopped turn, then retry the original thread. Do not disable hooks, mark acceptance checks passed, or mark the task complete. The recovery must be verified against the actual hook and ledger. This handles the custom checkpoint policy; unrelated task blockers still need resolution.
Activity