Skip to content

🤖 fix: stop heartbeats and background wakes from pausing goals - #3955

Open
ThomasK33 wants to merge 45 commits into
mainfrom
goals-c35v
Open

🤖 fix: stop heartbeats and background wakes from pausing goals#3955
ThomasK33 wants to merge 45 commits into
mainfrom
goals-c35v

Conversation

@ThomasK33

Copy link
Copy Markdown
Member

Summary

Scheduled heartbeats (and background wake turns) could leave active goals paused — or make already-paused goals look like they were still being touched. This PR fixes the three mechanisms behind the symptom: a queue race that auto-paused a freshly created goal, a fragile in-memory kickoff window that let any maintenance turn's getGoal() flip a never-driven goal to paused, and stream accounting that charged paused/complete goals for maintenance streams.

Background

Diagnosed from live session data (user report: "heartbeats are pausing goals"). In one session, a model-created goal was auto-paused ~500ms after creation by a user message that had been queued while the goal-creating turn was still streaming; heartbeat turns then ran for hours charging the paused goal ($7.11 / 8 turns, updatedAtMs bumped every turn) without ever driving it. In another, an active goal whose kickoff continuation was blocked by active_descendant_tasks survived only via the in-memory kickoff candidate — any candidate loss (restart, eviction) let the next getGoal() (tool assembly runs one on every heartbeat/wake turn) silently pause it via chat-tail reconciliation.

Implementation

  1. Queue-race guardMessageQueue stamps each entry with lastAddedAtMs and dequeueNext() exposes it as enqueuedAtMs. applyManualUserMessageGoalSafety skips the auto-pause (and candidate clear) when goal.createdAtMs >= enqueuedAtMs: the user cannot have been intervening against a goal that did not exist when they typed. Messages typed after the goal exists still pause it; explicit Pause is unaffected.

  2. Durable kickoff windowapplyChatTailGoalMode no longer reconciles an active goal to paused off a manual-user chat tail when lastContinuationFiredAtMs == null. A never-driven goal has no goal_continuation row yet by construction, so its tail always ends at a pre-goal manual row; pausing on that is a false positive. This makes the kickoff window durable across restarts and candidate eviction, and self-healing: the next stream end re-arms the continuation instead of stranding the goal.

  3. Maintenance-stream accounting skiprecordStreamAccounting now skips paused/complete goals for all origins except goal_continuation / goal_budget_limit (previously only user was skipped). Heartbeats resolve to user origin and wake turns to other; neither should charge turns/cost or bump updatedAtMs on a goal that is not running. Mirrors attributeChildReport's existing paused/complete skip.

Validation

  • New regression tests: never-driven goals survive candidate loss; driven goals still pause on manual rows; queue-race in both directions (message predates goal → stays active, postdates → pauses); paused goals ignore "other"-origin accounting.
  • Full src/node/services sweep: the only failures (BackupRepoCache, TaskService recovery, agent_skill_delete) reproduce identically on a clean-HEAD probe worktree — pre-existing host issues, not regressions.

Risks

Goal lifecycle logic; moderate regression surface:

  • Fix 2 removes one pause path for never-driven goals. If a user manually intervenes during the kickoff window, the dispatch-time auto-pause (fix 1's guarded path) still handles it; only reconciliation-by-read is exempted. Worst case is a goal showing active instead of paused until its first continuation fires.
  • Fix 1 relies on enqueuedAtMs only being present on queue-dispatched sends; direct (idle) sends never carry it and keep today's behavior.
  • Fix 3 could under-charge a goal if a genuine goal-driven stream raced a pause with a mislabeled origin; goal-driven origins are threaded explicitly by AgentSession, so this is bounded to cost accounting, not control flow.

Generated with xum • Model: anthropic:claude-fable-5 • Thinking: xhigh • Cost: $49.89

Three mechanisms made scheduled heartbeats appear to pause active goals
(diagnosed from live session data):

1. Queue race: a message typed while the goal-creating turn was still
   streaming dispatched right after the queued set_goal applied and
   auto-paused the brand-new goal. MessageQueue now stamps entries with
   enqueuedAtMs, and goal safety skips the pause when the goal was
   created after the message was typed.

2. Fragile kickoff window: chat-tail reconciliation paused active goals
   whose in-memory kickoff candidate was lost (restart, eviction) before
   the first continuation fired — the next getGoal (heartbeat/wake tool
   assembly runs one every turn) silently flipped them to paused. Goals
   with lastContinuationFiredAtMs == null are now exempt from the
   active→paused manual_user reconciliation, making the kickoff window
   durable and self-healing.

3. Accounting noise: recordStreamAccounting charged paused/complete
   goals for maintenance streams (heartbeats, background wake turns),
   bumping updatedAtMs so every heartbeat looked like it had just
   touched the paused goal. Only goal-driven origins
   (goal_continuation / goal_budget_limit) now charge non-active goals,
   mirroring attributeChildReport.
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@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: e67e217ff9

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/agentSession.ts
Comment thread src/node/services/workspaceGoalService.ts Outdated
Comment thread src/node/services/workspaceGoalService.ts Outdated
@chatgpt-codex-connector

This comment has been minimized.

…econciliation, budget_limited accounting)

- P1: preserve the projected goal's createdAtMs through the mid-stream
  drain so interventions queued against the visible optimistic goal are
  not misread as pre-goal input.
- P2: persist enqueuedAtMs on queue-dispatched user rows and scope the
  never-driven kickoff exemption to rows authored before the goal
  existed; post-goal rows pause on reconciliation even when the
  dispatch-time auto-pause was lost to a crash.
- P2 (accounting): extend the maintenance-stream skip to budget_limited
  goals so background wakes cannot inflate the recorded overshoot.
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@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: 02ab4595ee

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/agentSession.ts
Comment thread src/node/services/workspaceGoalService.ts
…e maintenance cost previews

- Rejected manual sends (pricing gate) now persist timestamp +
  enqueuedAtMs so chat-tail reconciliation can classify the row as
  pre-goal after a restart instead of pausing a never-driven goal.
- previewStreamAccounting receives the stream origin kind and mirrors
  final accounting's budget_limited maintenance skip, so the Goal UI no
  longer shows climbing heartbeat/wake cost that snaps back at stream
  end.
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@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: 4bd9a185f4

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/workspaceGoalService.ts
Codex P2: createGoal() stamped createdAtMs before the kickoff-model
validation and streaming re-check awaits, so a message queued during
those awaits postdated the stamp yet predated goal visibility, and the
pre-goal guard misread it as an intervention. Re-stamp fresh projected
goals immediately before publishPendingGoalSnapshot.
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@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: e712711382

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/workspaceGoalService.ts
Comment thread src/node/services/agentSession.ts Outdated
@chatgpt-codex-connector

This comment has been minimized.

…off candidate on ack failure

Codex P2 x2: (1) the round-3 stamp still preceded the async
activity-snapshot read inside publishPendingGoalSnapshot, so a message
queued during that read postdated the stamp while the renderer had not
yet received onActivityChange — publish first, then stamp fresh goals.
(2) reordering acknowledgeUser before the candidate clear meant an
acknowledgment throw skipped the clear entirely, letting a stale kickoff
candidate dispatch a continuation despite the user's persisted
intervention — clear conservatively on failure, then rethrow.
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

This comment has been minimized.

@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: 930f18846d

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/messageQueue.ts Outdated
Comment thread src/node/services/workspaceGoalService.ts Outdated
…ure authoring time at request entry

Codex P1: round 4 moved pendingGoalMutations.set after the publication
await, so a user abort landing during publication deleted nothing and
the setter then installed the mutation anyway — resurrecting a goal the
abort discarded and silently applying it at the next stream end. Install
before publish; guard the post-publication re-stamp on mutation identity
so an interleaved abort (or competing setter) is never overwritten.

Codex P2: lastAddedAtMs was sampled at enqueue, after WorkspaceService
preflight awaits (pricing gate, settings persistence) — a goal becoming
visible during those awaits postdated the user's authoring. Capture
authoredAtMs at request entry and thread it through queueMessage /
MessageQueue, the pricing-rejection delegation, and direct sends.
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@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: 1340998494

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/workspaceGoalService.ts

@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 Security Review

Here are some automated security review suggestions for this pull request.

Reviewed commit: 1340998494

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

Comment thread src/node/services/messageQueue.ts Outdated
…ublication setter

Codex P2: a stream ending during the setter's publication await let
applyPendingAfterStreamEnd take the mutation synchronously (outside the
goal file lock) and persist the pre-publication construction stamp — a
message authored during the publication await was then misclassified as
a post-goal intervention. The drain now flushes the lock and re-reads
the mutation, draining the finalized publication stamp (or honoring a
discard that landed in the same window).
…hed sends

Codex security P2: overlapping sends can complete preflight out of
authoring order, letting an older pre-goal message overwrite a later
post-goal stop/correction's authoring time — the batch then satisfied
the pre-goal guard and kept the goal running despite the intervention.
Fold each add's authoring time in via max(); seed entry creation with 0
so an authoredAtMs captured before slow preflight is never swallowed by
the creation wall clock.
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@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: a9b94d898d

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/workspaceGoalService.ts Outdated
…al-safety comparisons

Codex P2: chat.jsonl rows are unchecked JSON, so a malformed
enqueuedAtMs (negative/NaN/string) could beat a valid row timestamp in
the nullish selection and misclassify a genuine post-goal intervention
as pre-goal, leaving a never-driven goal running after restart. Only
finite non-negative numbers participate; invalid values fall back to
the validated row timestamp.
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

This comment has been minimized.

@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: 04e46a95a8

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/workspaceGoalService.ts Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

This comment has been minimized.

@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: 27927435b9

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/agentSession.ts Outdated
Reject malformed goal attribution at the unchecked compaction-summary boundary, clear the corrupt pending follow-up, and forward only validated values into goal recovery.

---

_Generated with `xum` • Model: `anthropic:claude-fable-5` • Thinking: `xhigh` • Cost: `$502.42`_

<!-- mux-attribution: model=anthropic:claude-fable-5 thinking=xhigh costs=502.42 -->
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@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

const result = await goalService.setGoal({
workspaceId: this.workspaceId,
status: "paused",
initiator: "auto",
});

P1 Badge Scope auto-pause to the acknowledged goal

When acknowledgeUser() returns active goal A but a replacement active goal B persists before this call acquires the goal lock, the unguarded status mutation re-reads and pauses B even though the manual row predates B. The earlier pre-goal classification used A's creation time, and the unscoped candidate clear can also remove B's kickoff, leaving the replacement stranded. Fresh evidence beyond the resolved goal-scoped wrap-up-suppression thread is that this durable auto-pause path still carries no goal identity; pass A's expectedGoalId and clear only A's candidate, or re-read and classify the replacement before applying either side effect.

AGENTS.md reference: AGENTS.md:L150-L150

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/agentSession.ts
Comment thread src/node/services/agentSession.ts Outdated
…idate retry goal IDs

Carry the queue/busy idle rule through the redispatched follow-up's send-admission gates, treat stale-admission refusals as skips, and discard startup-retry goal attribution when the persisted goal ID is present but malformed.

---

_Generated with `xum` • Model: `anthropic:claude-fable-5` • Thinking: `xhigh` • Cost: `$502.42`_

<!-- mux-attribution: model=anthropic:claude-fable-5 thinking=xhigh costs=502.42 -->
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

This comment has been minimized.

@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: 9f4cad147d

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/agentSession.ts
Comment thread src/node/services/workspaceGoalService.ts Outdated
Comment thread src/node/services/workspaceGoalService.ts
…ation; recovered wrap-up reservation

Expose WorkspaceService send preflights to redispatched follow-up idle probes, validate goal-scoping IDs against the durable UUID contract, and install the missing wrap-up reservation when a crash-recovered budget follow-up dispatches.

---

_Generated with `xum` • Model: `anthropic:claude-fable-5` • Thinking: `xhigh` • Cost: `$502.42`_

<!-- mux-attribution: model=anthropic:claude-fable-5 thinking=xhigh costs=502.42 -->
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

This comment has been minimized.

@chatgpt-codex-connector

This comment has been minimized.

@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: c205e21ba1

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/workspaceService.ts Outdated
Comment thread src/node/services/agentSession.ts Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@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

const result = await goalService.setGoal({

P1 Badge Scope the automatic pause to the acknowledged goal

When a manual message acknowledges goal A while a concurrent replacement B is queued behind that acknowledgment's goal-file lock, B can become durable before this setGoal() obtains the lock. Because the pause carries no expectedGoalId, it then resolves the current objective and pauses B, even though the message predates B; the earlier workspace-wide candidate deletion can also remove B's kickoff. Fresh evidence beyond the resolved goal-scoped wrap-up suppression is that the subsequent automatic pause remains unscoped; pass A's goal ID as the expected identity and treat a replacement conflict as a no-op.

AGENTS.md reference: AGENTS.md:L150-L150

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/workspaceService.ts Outdated

@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 Security Review

Here are some automated security review suggestions for this pull request.

Reviewed commit: af844281ac

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

// silently pausing it half a second after creation (user report: goals
// "paused by heartbeats" were actually killed here, then heartbeat turns
// kept the workspace moving while the goal sat paused).
if (input.enqueuedAtMs != null && goal != null && goal.createdAtMs >= input.enqueuedAtMs) {

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 Security: Pause on queued stop messages before restoring kickoff

When a user queues a stop/correction while the current model turn is still streaming and that model publishes a new goal afterward, this timestamp-only branch treats the message as non-intervention, restores the kickoff candidate, and returns without pausing. The durable tail code makes the same pre-goal exemption, so the next idle pass can dispatch an exec continuation even if the model ignores the corrective turn. This lets a prompt-injected/untrusted model resume file/shell work after the documented “any manual turn pauses” boundary. Only bypass this pause for an explicit user opt-in, not merely enqueuedAtMs <= createdAtMs.

Useful? React with 👍 / 👎.

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

Security review completed. No security issues were found in this pull request.

Reviewed commit: b37d4b6ed1

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@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: b37d4b6ed1

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +2965 to +2969
const persisted = await this.persistGoalMutationLocked(input, options);
// Arm under the same lock tenure as the paused write so no other locked
// writer can observe the paused record before the hold exists.
if (this.pauseFinalizationHoldApplies(input, persisted) && persisted.success) {
this.armPauseFinalizationHold(input.workspaceId, persisted.data.goalId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Arm Pause invalidation before publication awaits

When a captured continuation is in send preflight and Pause commits goal.json, persistGoalMutationLocked() still awaits snapshot/preview publication before returning here and bumping explicitPauseGenerations; during that window the candidate, pause generation, terminal generation, and identity generation all remain unchanged, so admissionStale can admit an autonomous exec turn after the durable Pause. Fresh evidence beyond the resolved Pause-admission thread is this publication gap before armPauseFinalizationHold() is reached; arm the hold/generation immediately at the paused write commit.

AGENTS.md reference: AGENTS.md:L150-L150

Useful? React with 👍 / 👎.

});
}

sessionInvisiblePreflight.release();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep resume preflights visible through session admission

When startup follow-up recovery races a user/API Resume, this releases the only hasExternalSendPreflight signal before AgentSession.resumeStream() runs its second asynchronous pricing check. The session is still idle during that await, so dispatchPendingFollowUp() can admit the recovered synthetic turn; after pricing resolves, resumeStream() does not recheck isBusy() and can start the resumed turn concurrently. Fresh evidence beyond the resolved send-preflight threads is this separate resume handoff; retain the reservation until session admission settles or recheck busy state after the inner preflight.

AGENTS.md reference: AGENTS.md:L150-L150

Useful? React with 👍 / 👎.

@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 Security Review

Here are some automated security review suggestions for this pull request.

Reviewed commit: b37d4b6ed1

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

// Handoff: from here the send is the session's own admission problem —
// release the probe reservation so a follow-up redispatched from within
// this very turn (on-send compaction completion) does not veto itself.
sessionInvisiblePreflight.release();

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 Security: Keep accepted manual sends visible until AgentSession is busy

Requires a goal-scoped compaction follow-up being recovered while an accepted manual send enters AgentSession. This line releases the only follow-up-visible reservation before AgentSession claims PREPARING; fresh evidence beyond the prior preflight threads is that AgentSession immediately yields at await cancelBeforeAcceptance() and does not claim PREPARING until line 3892. Recovery can therefore see no preflight, queue, or busy state and admit the exec follow-up ahead of the manual pause, allowing normal shell/file tools to run. Retain visibility until the session is synchronously busy, while excluding only the originating turn's own follow-up.

Useful? React with 👍 / 👎.

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.

1 participant