Skip to content

fix: run the stop-gate review as an ephemeral, untracked, read-only one-shot#385

Open
joelmdev wants to merge 1 commit into
openai:mainfrom
joelmdev:fix/ephemeral-stop-gate-review
Open

fix: run the stop-gate review as an ephemeral, untracked, read-only one-shot#385
joelmdev wants to merge 1 commit into
openai:mainfrom
joelmdev:fix/ephemeral-stop-gate-review

Conversation

@joelmdev

Copy link
Copy Markdown

Problem

When the stop-time review gate is enabled, the Stop hook runs codex-companion.mjs task on every turn. The task path always set persistThread: true (persisting the thread as an on-disk rollout) and registered a tracked job in the companion catalog (state.json + jobs/<id>.{json,log}).

But the stop-gate review is a one-shot: the hook consumes its result inline (parsing ALLOW:/BLOCK: from stdout) and never resumes or inspects it via /codex:status, /codex:result, or --resume-last. So every turn leaves behind:

  • a persisted Codex rollout on disk, and
  • a "Codex Stop Gate Review" job that churns through the 50-job catalog cap, pushing out real tasks and reviews.

On a busy machine this accumulates into hundreds of orphaned rollouts and a catalog dominated by stop-gate noise.

Fix

Route the stop-gate one-shot (already recognized via STOP_REVIEW_TASK_MARKER) through an ephemeral, untracked, read-only path in handleTask:

  • executeTaskRun now honors request.persistThread (default true), so the stop-gate passes persistThread: false → the thread starts ephemeral: true (no rollout) with no persistent thread name.
  • The stop-gate skips runForegroundCommand / runTrackedJob, so no job record or log file is written. The same JSON payload is still printed to stdout, so the hook contract (and the gate's ALLOW/BLOCK behavior) is unchanged.
  • The marker check runs before the --background branch, so a backgrounded marker prompt can't create a tracked job either.
  • The stop-gate omits write, so the review can never select a workspace-write sandbox regardless of CLI flags — it is always read-only.

Normal /codex:task runs are unaffected (persistThread defaults to true).

Tests

Updated the stop-hook end-to-end test to assert the new contract: the review still runs and blocks on findings, the review thread is ephemeral, and no "Codex Stop Gate Review" job is added to the catalog.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Codex stop-time review gate execution path so the stop-gate “one-shot” review runs as an ephemeral, untracked, read-only task, preventing orphaned persisted threads and job-catalog churn while keeping the hook’s stdout contract intact.

Changes:

  • Teach executeTaskRun to honor request.persistThread (defaulting to true) and avoid generating a persistent thread name when persistence is disabled.
  • Route stop-gate marker prompts through a foreground, untracked one-shot path in handleTask that forces persistThread: false and omits write (read-only).
  • Update the stop-hook end-to-end test to assert the thread is ephemeral and that no “Codex Stop Gate Review” job appears in the catalog/status output.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
tests/runtime.test.mjs Adds assertions that stop-gate runs produce an ephemeral thread and do not create catalog jobs/status entries.
plugins/codex/scripts/codex-companion.mjs Implements persistThread support in task execution and adds an early stop-gate one-shot execution path that bypasses tracked jobs and forces read-only.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5406e18692

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

resumeLast
});

if (!resumeLast && String(prompt ?? "").includes(STOP_REVIEW_TASK_MARKER)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Gate only internal stop-review invocations

Any normal /codex:task prompt or --prompt-file that contains this marker sentence now takes the stop-gate path before --background or --write are honored. For example, asking Codex to edit or discuss plugins/codex/prompts/stop-review-gate.md with --write would be run as an untracked ephemeral read-only one-shot instead of a write-capable task, so the requested edits cannot be made and the job cannot be resumed or inspected. Consider keying this branch off an internal flag/env from stop-review-gate-hook.mjs rather than user-controlled prompt text alone.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 4acaf32. Routing no longer reads the prompt: stop-review-gate-hook.mjs now passes an explicit --stop-gate flag, and handleTask keys the ephemeral/untracked/read-only branch off that flag instead of the marker sentence. So a normal /codex:task (or --prompt-file) whose text happens to contain the marker — e.g. editing prompts/stop-review-gate.md with --write — now runs as a normal write-capable, tracked, resumable task. Added a regression test asserting exactly that. Thanks for the catch!

…ne-shot

When the stop-time review gate is enabled, the Stop hook runs
`codex-companion.mjs task` every turn. That path forced
`persistThread: true` (persisting the thread as an on-disk rollout) and
registered a tracked "Codex Stop Gate Review" job in the companion
catalog (state.json + jobs/<id>.{json,log}).

But the stop-gate review is a one-shot: the hook consumes its result
inline (parsing ALLOW:/BLOCK: from stdout) and never resumes or inspects
it via /codex:status, /codex:result, or --resume-last. So every turn
orphaned a Codex rollout on disk and churned the 50-job catalog cap with
stop-gate noise, pushing out real tasks and reviews.

stop-review-gate-hook.mjs now marks its invocation with an explicit
`--stop-gate` flag, and handleTask routes on that flag (not
user-controlled prompt text) through an ephemeral, untracked, read-only
path: the check runs before the --background branch (so a backgrounded
run can't create a tracked job), passes persistThread: false (ephemeral
thread, no rollout, no thread name), and omits write so the review can
never select a writable sandbox. executeTaskRun now honors
request.persistThread (default true). The stdout contract is unchanged;
normal /codex:task runs are unaffected, even when their prompt text
happens to contain the stop-gate marker sentence.
@joelmdev joelmdev force-pushed the fix/ephemeral-stop-gate-review branch from 5406e18 to 4acaf32 Compare June 26, 2026 15:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants