Skip to content

Remove the temporary copy when saving a Bot's browser control fails - #653

Merged
davidmckayv merged 2 commits into
CopilotKit:mainfrom
kevin9327:fix/control-store-temp-cleanup
Sep 28, 2026
Merged

davidmckayv merged 2 commits into
CopilotKit:mainfrom
kevin9327:fix/control-store-temp-cleanup

Conversation

@kevin9327

Copy link
Copy Markdown
Contributor

What this changes

createControlStore keeps who holds a Bot's browser, and its handoff requests, in .control/<bot>.json under the profiles volume. save writes the state to <bot>.json.<uuid>.tmp and renames it over the real file. When the write or the rename threw (disk full, a file that cannot be replaced), the temporary file was left where it was: a second, readable copy of the control state, and one more for every later failure. The existing test already holds that a save leaves .control with only bot-1.json in it; that held only while every save succeeded.

save now removes the temporary in a finally, whether or not the rename happened, the same shape scripts/setup-learning.ts (saveEnvironment) and server/src/provider-oauth.ts use for their atomic writes. After a successful rename the path no longer exists, and rmSync with force does nothing. The error from the write or rename still propagates unchanged.

Where it runs

OpenBot is deployed as several server processes behind a load balancer, serving a whole company.
Consecutive requests from the same person reach different processes, and the process that answered a
WebSocket upgrade is rarely the one that answers the next call on that conversation.

State that outlives a single request therefore has to be shared, or the change works on one machine
and stops working the moment there are two, without saying so. That failure is worse than not
shipping the feature: it passes review, passes CI, passes a local demo, and only surfaces as a Bot
that forgets, a question nobody can answer, or a boundary that never fires.

Answer these even when the answer is "none":

  • New state that outlives a request? None. The state file is the one the computer already keeps; this removes a stray copy of it.
  • What happens on the second replica? The same. Each computer writes only its own Bot's file.
  • Anything serialised? None added. The write-then-rename is unchanged.
  • Anything fanned out to a browser? None.
  • New listener, port, or schedule? None.

Boundary and audit

  • Every acting call still goes through the gateway: resolve, decide, audit, then act. Untouched.
  • New refusals and new failures each write a row. None added; a failed save still throws as before.
  • Nothing new is trusted from the client that the server can resolve itself.

Changelog

  • A line in CHANGELOG.md under Unreleased.

Proof

New test in agent-computer/tests/control-store.test.ts: a directory where bot-1.json goes, so the rename fails, then .control is listed. On unmodified main:

- Expected  - 0
+ Received  + 1
(fail) a save that cannot replace the state leaves no temporary copy behind

After the fix: bun test tests/control-store.test.ts in agent-computer → 7 pass, 0 fail. tsc --noEmit in agent-computer exits 0. Biome check clean on the changed files.

🤖 Generated with Claude Code

The control store wrote its state to a temporary file and renamed it
over the real one, but a write or rename that threw left the temporary
behind. It is now removed in a finally, as the other atomic writers do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

davidmckayv
davidmckayv previously approved these changes Sep 28, 2026
Move the unchanged changelog entry to its own existing anchor.
@davidmckayv
davidmckayv merged commit 874b1f8 into CopilotKit:main Sep 28, 2026
17 checks passed
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