Skip to content

fix: read MCTS params per-request instead of mutating shared global (#304)#314

Merged
codelion merged 2 commits into
algorithmicsuperintelligence:mainfrom
SuperMarioYL:fix/mcts-params-request-scoped-304
Jul 4, 2026
Merged

fix: read MCTS params per-request instead of mutating shared global (#304)#314
codelion merged 2 commits into
algorithmicsuperintelligence:mainfrom
SuperMarioYL:fix/mcts-params-request-scoped-304

Conversation

@SuperMarioYL

Copy link
Copy Markdown
Contributor

Summary

Fixes #304 — a race condition where concurrent requests corrupt each other's MCTS parameters through shared global state.

proxy() wrote the request's mcts_depth / mcts_exploration / mcts_simulations into the module-level server_config on every request, and execute_single_approach() read them back out of that same global:

# proxy()  (server.py)
server_config['mcts_depth']       = data.get('mcts_depth', server_config['mcts_depth'])
server_config['mcts_exploration'] = data.get('mcts_exploration', server_config['mcts_exploration'])
server_config['mcts_simulations'] = data.get('mcts_simulations', server_config['mcts_simulations'])
...
# execute_single_approach()
return chat_with_mcts(..., server_config['mcts_simulations'],
                           server_config['mcts_exploration'],
                           server_config['mcts_depth'], ...)

Under Flask's default threaded mode (or gunicorn / uWSGI / Hypercorn), two concurrent requests race on that global: request B overwrites request A's params between A's write and A's read, so A silently runs MCTS with B's settings. As a secondary effect, a request that sets any mcts_* value also persistently mutates the global for every later request.

Fix

Every other request parameter already flows bottom-up through the per-request request_config dict. MCTS was the lone leftover pushing into shared mutable state. The fix makes it consistent with the rest:

  • execute_single_approach() now reads the MCTS params from request_config (with the server_config defaults as fallback) instead of the global.
  • proxy() no longer writes them back into server_config.

Because a client-sent mcts_* value is already copied into request_config from the request body, and the fallback resolves to the server/CLI defaults otherwise, behaviour is unchanged for every caller — including the "user set --simulations globally and never sends a per-request override" path — while the shared global is now read-only per request, so there is nothing left to race on.

The change is intentionally scoped to mcts. bon (best_of_n) and rstar read their params from server_config too, but they are never written back per-request, so they have no write-then-read race — #304 is specifically the MCTS write-back.

Testing

Added regression tests to tests/test_approaches.py (runs in the existing unit-tests CI job):

  • test_mcts_params_are_request_scoped — a per-request mcts_* value reaches chat_with_mcts; with no per-request value the server default is used (CLI-default path); the global is not mutated.
  • test_proxy_does_not_mutate_global_mcts_config — drives a real request through the Flask /v1/chat/completions handler with per-request MCTS params and asserts the shared global server_config is left untouched while the per-request values still reach the approach.

Both tests fail on main (the per-request read returns the stale global default; the proxy mutates the global) and pass with this change.

SuperMarioYL and others added 2 commits July 4, 2026 17:45
…lgorithmicsuperintelligence#304)

proxy() wrote the request's mcts_depth/mcts_exploration/mcts_simulations
into the module-level server_config on every request, and
execute_single_approach read them back out of that same global. Under
Flask's threaded mode (or gunicorn/uWSGI), concurrent requests overwrite
each other's MCTS parameters between the write and the read, silently
corrupting results. The write also leaked one request's params into every
subsequent request.

Resolve the params from the per-request request_config (with the server
defaults as fallback) and stop writing them into the shared global, so
each request uses its own values with no cross-request interference.

Add regression tests covering the per-request read, the CLI-default
fallback, and an end-to-end proxy check that the global is no longer
mutated by a request.

Fixes algorithmicsuperintelligence#304
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codelion codelion merged commit 6901e2d into algorithmicsuperintelligence:main Jul 4, 2026
5 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.

Bug: Race condition — concurrent requests corrupt MCTS parameters via shared global state

2 participants