Skip to content

🤖 perf: bind xum server listener before startup recovery; stop per-task config.json reloads - #4058

Queued
ibetitsmike wants to merge 28 commits into
mainfrom
mike/server-bind-before-recovery
Queued

🤖 perf: bind xum server listener before startup recovery; stop per-task config.json reloads#4058
ibetitsmike wants to merge 28 commits into
mainfrom
mike/server-bind-before-recovery

Conversation

@ibetitsmike

@ibetitsmike ibetitsmike commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Summary

xum server now binds its port after the fast core init plus agent-task restart recovery, and runs the O(workspaces)/O(reported tasks) startup housekeeping in the background, so time-to-listen depends on the number of active tasks rather than on deployment size. The housekeeping loops also stop re-parsing config.json once per reported task, the terminal-attention pending scan is bounded-concurrent, slow startup passes are logged at warn, and AnalyticsService.dispose() waits for its worker so a signal during the startup DuckDB sync no longer aborts the process. Fixes #4055.

Background

On a deployment with 1,535 workspaces (343 reported tasks, 18 GB sessions dir) xum server took 13 minutes to bind its port because src/cli/server.ts awaited serviceContainer.initialize() before startServer(), and TaskService.initialize spent ~776 s in sequential recovery: a sequential scan of every session dir for pending terminal-attention records (306 s), patch-generation recovery with a synchronous 2.47 MB config parse per reported task (205 s), and reported-task cleanup with another parse per task (131 s). Clients got connection refused the whole time and Coder marked the app unhealthy. See #4055 for the measured timeline.

The part of startup that actually has to precede clients is small: reconciling execution handles, fixing stale starting tasks, draining the queue, and prompting the handful of awaiting_report/running tasks to continue. Everything that scales with deployment size (patch artifacts and cleanup for every reported task, the session-dir scan, workflow garbage sweeps, chat restart retries, orphan sweeps) is housekeeping that is idempotent and already runs against live state at runtime.

Implementation

  • TaskService.initialize() is split into recoverInterruptedTasks() (execution-handle reconciliation, stale-starting fixup, queue drain, inactive-workflow-owner prepass, awaiting_report/running restart prompts; bounded by the number of active tasks) and runStartupHousekeeping({ signal }) (patch-artifact recovery, best-of delivery, reported-task cleanup, workflow archive sweep, terminal-attention sweeps and drains). initialize() still runs both for desktop startup and tests.
  • ServiceContainer.initialize() is split the same way: initializeCore() (extensionMetadata, telemetry, policy, experiments, then taskService.recoverInterruptedTasks()) and runStartupHousekeeping() (workspaceService.initialize(), taskService.runStartupHousekeeping(), then the idle-compaction/heartbeat/agent-status starts and the completion log). server.ts awaits initializeCore(), starts the server, then runs runStartupHousekeeping() in the background with an error handler; dispose() aborts the housekeeping signal and joins the in-flight step (bounded by STARTUP_HOUSEKEEPING_JOIN_TIMEOUT_MS, 500 ms) so a shutdown mid-housekeeping stops at the next step boundary before the services it uses are torn down, and never starts periodic services against disposed dependencies; the transient chat-recovery sessions that housekeeping scheduled are disposed right after that join (their chains re-check disposed before every dispatch), with backgroundProcessManager.beginShutdown() still the first teardown step so none of those disposals can erase persisted armed-monitor records, and workspaceService.initialize({ signal }) schedules none once shutdown began. Desktop startup is unchanged (initialize()).
  • Because task recovery completes before the listener exists, no client can race its status transitions or sends, so it needs no compare-and-set or admission probes. Only the post-listen housekeeping can overlap with clients, and every step there re-checks live state before it mutates:
    • Reported-task cleanup screens candidates on the loop's config snapshot and confirms eligibility on fresh config as a beforeRemove precondition that WorkspaceService.remove() evaluates inside its task-tree lifecycle lock (the lock reactivation, re-parenting, and task_stop all mutate under). That confirmation also rejects a task whose execution mirror (taskExecutionStatus) is starting or running, which is the state an existing-workspace turn leaves before its stream registers, and the lineage walk continues from the parent the live confirmation saw (a re-parent since the screen).
    • Best-of finalization of a crash-left parent partial (tryFinalizePendingTaskToolCallInPartial, also the runtime child-report path) is now a compare-and-set: HistoryService.updatePartialIfMessageIdMatches() re-reads the partial under the per-workspace file lock and writes only while it is still the same message with the task call still pending and no stream running. A parent turn that starts meanwhile (client send, or a resumed child's task_send_message) commits that partial and writes its own under a new id, so the finalization is dropped instead of resurrecting or overwriting it. commitPartial() is now one transaction under the same pair of locks the CAS holds (the workspace mutex and the cross-process history write lock): snapshot, history append/update/delete, and partial delete cannot interleave with the CAS or with another backend's commit of the same partial, so a finalization is either included in the commit or declined, never appended pre-update and deleted. The lock-held bodies of appendToHistory/updateHistory/deleteMessage/getHistoryFromLatestBoundary were extracted for that (their public wrappers are unchanged).
    • Patch-artifact recovery passes the loop snapshot via maybeStartGeneration(..., { config }); a snapshot child with no artifact yet, or with a crash-left pending one, is re-checked on live config before generation runs, and skipped when it was removed or reactivated (active workspace-turn execution) or is streaming. Reactivated tasks get their artifact from the existing continuation refresh when that execution settles.
    • Chat restart recovery re-reads config right before scheduling (skipping workspaces archived or removed since the metadata read), and archive() disposes a workspace's still-pending transient recovery session once archivedAt is durable; a recovery scheduled on a session a client had already created is not disposed by archive, so the two internal dispatch points of startup recovery (pending compaction follow-up, startup auto-retry) re-read the durable archived state right before dispatching, mirroring the guard WorkspaceService.sendMessage already applies; the orphan scratch-workdir sweep gained the session sweep's grace window and fresh-config recheck; the DevTools-log sweep re-checks live archive state under the task-tree lock before each deletion.
  • TerminalAttentionStore.listPendingOwnerWorkspaceIds() scans session dirs through an AsyncSemaphore(16) and short-circuits per owner on the first pending record.
  • [startup] ... completed logs use log.warn when totalMs exceeds SLOW_STARTUP_WARN_THRESHOLD_MS (30 s, src/constants/startup.ts).
  • AnalyticsService.dispose() waits for the analytics worker to exit instead of tearing it down mid-native call. With the graceful SIGINT handler installed while the startup DuckDB sync may still be running, exiting the process mid-sync tore the worker down inside native DuckDB and aborted the process (Napi::Error -> SIGABRT); UAT reproduced this 7/8 times before the fix.

Validation

Remote dogfood UAT ran on a Coder Agents workspace against an earlier head of this branch (one where all recovery, including the task prompts, ran post-listen) and main with identical synthetic roots (config.json with 1,500 to 8,000 workspaces, 300 to 2,000 reported tasks, session dirs with terminal-attention records), driving the real UI with a real model:

  • Time-to-first-/health 200 at N=1,500: 2.7 to 3.9 s (branch) vs 12.8 s (main); at N=8,000 with 1,500 reported tasks: 2.2 s, while background housekeeping took ~57 s. The current head additionally awaits the task recovery phase before binding; that phase is bounded by the number of active tasks (0 to 2 in the measured deployments, sub-second) rather than by N.
  • UI, /api/docs, and a 150-request hammer stayed healthy during housekeeping; a workspace created during housekeeping persisted with a clean 2-turn chat; kill -9 mid-housekeeping restarted cleanly; a second server on the same root was refused by the lockfile.
  • cleanupReportedTasksMs stayed flat as config grew 16x (111 to 173 ms vs 701 to 8,479 ms on main); terminalAttentionDrainMs over 8,001 session dirs was 209 ms; pendingTerminalAttentionOwnerWorkspaceCount was exact (3 of 3), including with a corrupt record and a stray file in sessions/.
  • SIGINT/SIGTERM during the startup analytics sync: 0/26 aborts after the dispose fix (7/8 before), all exit 0.
  • Unit coverage for the split: initializeCore waits for task recovery and does not run housekeeping; recoverInterruptedTasks resumes running tasks without touching reported ones while runStartupHousekeeping prunes reported tasks without resuming anything; best-of finalization leaves a parent partial that a live turn replaced mid-finalization untouched (red-green); dispose aborts in-flight housekeeping before the periodic services start; the snapshot patch path skips removed and reactivated children (red-green).

Risks

  • Requests can arrive while housekeeping runs. Its steps are the same passes the runtime already executes against live state (cleanup rechecks, terminal-attention sweeps on a timer, chat retry sessions) plus the live re-checks listed above; task recovery itself finishes before the listener opens. Desktop behavior is unchanged.
  • The early lockfile check in server.ts remains a fast-fail nicety, as on main: task recovery runs before startServer() acquires the lock, so two servers racing on one root could both attempt recovery; startServer() still refuses the second one.
  • UAT (Medium, not fixed here): SIGINT/SIGTERM while the startup analytics sync is mid-checkpoint now exits cleanly but slowly (11.5 to 13.6 s at N=1,500 and N=8,000). The main thread parks while one worker thread finishes the DuckDB checkpoint/close, and the 5 s Cleanup timed out, forcing exit path does not take effect in that state. A docker stop with a 10 s grace period would SIGKILL mid-checkpoint. Bounding or interrupting the checkpoint is a follow-up.
  • Residual: when patch generation actually runs at startup (artifacts left pending by a crash), each completion still triggers a cleanup recheck that reloads config, so patchGenerationRecoveryMs still grows with config size in that case. It is off the connect path now.
  • WorkspaceService.initialize chat-restart recovery with thousands of non-task workspaces is noisy (MaxListenersExceededWarning); pre-existing and unchanged.
  • Pre-existing lock nesting, unchanged by this PR: runtime cleanup callers reach cleanupReportedLeafTask under the workspace event lock and WorkspaceService.remove() then takes the task-tree lifecycle lock (event -> tree), while task_send_message takes tree -> event. This PR adds no acquisition on that path.

Pains

Eleven Codex rounds found one race after another between background recovery and early clients while the whole of TaskService.initialize ran post-listen (stop vs restart nudge, reactivation vs patch artifact, unarchive vs DevTools sweep, workflow resume vs child interrupt, ...), each fixed with another compare-and-set or lock. Moving the small state-mutating recovery phase back in front of the listener removed that whole class along with the admission probes, idle-only sends, refunds, run-keyed workflow admissions, and settlement-lock compare-and-set they had accumulated (net about 120 production and 360 test lines), and left only idempotent housekeeping behind the listener.


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

… config reloads (#4055)

- ServiceContainer.initialize() split into initializeCore() (fast) and
  runStartupRecovery() (O(workspaces) task/workspace recovery); `xum server`
  binds its port after core init and runs recovery in the background.
- Recovery snapshots config synchronously before its first await so tasks
  created by clients after listen are never treated as stale `starting`
  tasks; running-task resume skips tasks that are already streaming.
- Startup patch-generation and reported-task cleanup loops reuse one config
  snapshot instead of re-parsing config.json per task.
- TerminalAttentionStore.listPendingOwnerWorkspaceIds scans session dirs
  with bounded concurrency and short-circuits on the first pending record.
- [startup] completion logs switch to warn above SLOW_STARTUP_WARN_THRESHOLD_MS.
@chatgpt-codex-connector

This comment has been minimized.

@ibetitsmike

Copy link
Copy Markdown
Contributor 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: 5f89fb0cec

ℹ️ 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/cli/server.ts Outdated
Comment thread src/node/services/serviceContainer.ts Outdated
Comment thread src/node/services/serviceContainer.ts Outdated
- Capture the recovery config snapshot before startServer() opens the
  listener (it accepts requests while awaiting the lockfile/mDNS), and pass
  it into runStartupRecovery().
- Orphan scratch workdir sweep skips recently touched dirs and re-checks
  fresh config before deleting, so createScratch during recovery is safe.
- Isolate workspace/task recovery failures so the periodic services
  (idle compaction, heartbeat, agent status) always start.
@ibetitsmike

Copy link
Copy Markdown
Contributor 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: 314818f428

ℹ️ 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/taskService.ts Outdated
Comment thread src/node/services/taskService.ts
Comment thread src/cli/server.ts Outdated
…anges

- Stale-starting recovery compare-and-sets: only entries still `starting`
  are rewritten, so a task_stop that persisted `interrupted` wins.
- Running-task resume re-reads the live status before nudging, so a task
  stopped after the snapshot is not restarted.
- WorkspaceService.initialize re-reads config right before scheduling chat
  startup recovery, skipping workspaces archived or removed since the
  metadata read.
@ibetitsmike

Copy link
Copy Markdown
Contributor 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: 6aa18ab264

ℹ️ 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/taskService.ts Outdated
Comment thread src/node/services/serviceContainer.ts Outdated
Comment thread src/node/services/serviceContainer.ts
…p and unarchive

Startup recovery now runs while clients are connected, so every one-shot read it
makes before a mutation can go stale:

- The pending-guidance replay, restart nudge, and awaiting_report completion
  prompt carry an admissionStale probe. A task_stop that lands between the live
  status read and turn admission now refuses the send instead of resurrecting
  the stopped task through markInterruptedTaskRunning.
- reconcileAgentTaskExecutionIds compare-and-sets its mirror write under the
  per-handle settlement lock, so a stop that settled the handle during the
  liveness check keeps its terminal mirror and no stale live registration is
  installed.
- cleanupArchivedDevToolsLogs re-checks the live archive state under the
  task-tree lock before each deletion. DevToolsService.hasWorkspaceData gates
  that fresh config read so it only happens for actual deletions, not once per
  archived workspace.

Copy link
Copy Markdown
Contributor Author

@codex review

1 similar comment
@ibetitsmike

Copy link
Copy Markdown
Contributor Author

@codex review

Now that the graceful SIGINT handler is installed while the startup DuckDB
sync may still be running, exiting the process mid-sync tore the worker
down inside native DuckDB and aborted the process (Napi::Error ->
SIGABRT, 7/8 reproductions in UAT). AnalyticsService.dispose() now waits
(bounded by ANALYTICS_WORKER_SHUTDOWN_TIMEOUT_MS) for the worker to exit
after posting the shutdown message.
@ibetitsmike

Copy link
Copy Markdown
Contributor 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: f095888084

ℹ️ 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/analytics/analyticsService.ts Outdated
Comment thread src/node/services/workspaceTurnManager.ts Outdated
…nstalled execution handle

- AnalyticsService.dispose() now waits for the worker's exit event with no
  local bound. A 2 s timeout let dispose resolve while an ingest still held
  DuckDB open, so the caller's process.exit() reproduced the SIGABRT the wait
  exists to prevent. The outer quit budgets in cli/server.ts and
  desktop/main.ts already race the whole dispose and own the hard-exit
  decision. A worker that already exited short-circuits the wait.
- reconcileAgentTaskExecutionIds also compare-and-sets the workspace mirror
  pointer against its snapshot. A client that installs a new handle while
  reconciliation awaits the old handle's liveness check writes the mirror
  under a different settlement lock and leaves the old record unchanged, so
  the record-status check alone let the stale handle overwrite it.

Copy link
Copy Markdown
Contributor 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: 02cfc0a53a

ℹ️ 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/cli/server.ts Outdated
Comment thread src/node/services/taskService.ts
…and removed tasks

- interruptTaskRecoveryForInactiveWorkflowOwner leaves a child alone when a
  workflow resume is admitted for the run's workspace (checked synchronously
  inside the config edit via the workflow admission registry), so recovery
  cannot mark a freshly resumed run's child interrupted.
- maybeStartGeneration re-reads config before creating a pending artifact for
  a snapshot child that has no artifact yet, so a task removed since the
  startup snapshot does not get a new artifact.
@ibetitsmike

Copy link
Copy Markdown
Contributor 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: b460a3e682

ℹ️ 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/taskService.ts
Comment thread src/node/services/taskService.ts Outdated
…ity on live config

- Workflow admissions are tracked per run id as well as per workspace;
  startup recovery skips a stale child only when a resume of its own run is
  in flight, so unrelated runs in the same workspace no longer shield it.
- canCleanupReportedTask treats a caller snapshot as a screen only: any
  positive verdict is re-evaluated on freshly loaded config before the
  workspace is removed.
@ibetitsmike

Copy link
Copy Markdown
Contributor Author

@codex 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: 3a74713dbb

ℹ️ 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/serviceContainer.ts Outdated
A startup-recovery chain observes neither the housekeeping abort nor the
bounded join, so a recovery that was one await away from dispatching could
start a provider stream during the join window. Set the session shutdown
latch right after the abort, before waiting on housekeeping to settle.

Copy link
Copy Markdown
Contributor Author

@codex review

Round 19 (5cebf00): the session shutdown latch now lands before the housekeeping join, per the round-18 finding.

@chatgpt-codex-connector

This comment has been minimized.

Copy link
Copy Markdown
Contributor Author

@codex review

Retrying: the previous round-19 request on 5cebf00 failed with "Something went wrong".

@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: 5cebf008cf

ℹ️ 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

Copy link
Copy Markdown
Contributor Author

@codex review

Round 20 (08ca3a8): merged current main into the branch (no code changes of our own since 5cebf00). Main now carries the OpenAI 404 model_not_found classification fix via #4067, which is what made Test / Integration (modelNotFound) fail on the older base. The single Test / Unit failure on 5cebf00 (code_execution "guest Proxy vars swallows writes") was a QuickJS WASM "Unreachable code" crash while constructing a fresh runtime; it passes locally on both this branch and origin/main, and this PR touches no ptc/code_execution files.

streamWithHistory re-checked only the per-turn abortSignal after its awaits,
and internal retries carry none, so a retry that was mid-preparation when
shutdown began could still reach the provider. Fold disposed/shuttingDown into
the checkpoint predicate so every boundary before streamMessage honors it.

Copy link
Copy Markdown
Contributor Author

@codex review

Round 21 (1d4d77e): the round-19 finding is addressed, the shutdown latch is now re-read at every pre-stream checkpoint in streamWithHistory. The branch also carries current main (08ca3a8).

@chatgpt-codex-connector

This comment has been minimized.

Copy link
Copy Markdown
Contributor Author

@codex review

Retrying round 21 on 1d4d77e: the previous request returned "Something went wrong".

@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: 1d4d77ecd9

ℹ️ 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/taskService.ts
Comment thread src/node/services/taskService.ts
A reported best-of child that a client reawakened keeps its previous report
artifact while its continuation runs, and the grouped builder only checked that
every artifact exists. Revalidate each non-reporting sibling's execution and
stream state before assembling the grouped output, and treat such a sibling as
recoverable for the synthetic fallback so the parent waits for the new report.

Copy link
Copy Markdown
Contributor Author

@codex review

Round 22 (433e2bd): best-of finalization now revalidates sibling execution/stream state (round-21 P1 #2, fixed with a red-green test); the lock-order finding (round-21 P1 #1) is pre-existing on main and tracked in #4072 with line-level evidence in the thread.

@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: 433e2bda4f

ℹ️ 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/taskService.ts
Comment thread src/node/services/agentSession.ts
Comment thread src/node/services/agentSession.ts
Comment thread src/node/services/taskService.ts
…st-of assembly

Removal holds turn admission on the workspace's sessions for its whole
duration (released on failure), so startup recovery resuming from a disk read
cannot start work against a checkout being deleted. sendMessage refuses at the
pre-persist gate once the shutdown latch is set, so no follow-up row can read
as a dispatched turn on the next startup. Best-of assembly re-reads sibling
state after its artifact reads so a reactivation during those awaits cannot
ship the stale report it already collected.

Copy link
Copy Markdown
Contributor Author

@codex review

Round 23 (b795316): three of the round-22 findings are fixed (removal admission hold, pre-persist shutdown gate, post-read sibling revalidation), each with a red-green test; the CAS-supersession finding is answered in its thread as the pre-existing busy-parent delivery path.

@chatgpt-codex-connector

This comment has been minimized.

Copy link
Copy Markdown
Contributor Author

@codex review

Retrying round 23 on b795316: the previous request returned "Something went wrong".

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

ℹ️ 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/taskService.ts
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.

🤖 perf: xum server takes 13 min to bind its port on large deployments; TaskService.initialize runs O(workspaces) sequential recovery before listen()

1 participant