Skip to content

Small follow-ups: dead openenv_core fallbacks, quoted git args, collect loop threads - #1397

Merged
sergiopaniego merged 7 commits into
mainfrom
fix-small-followups
Oct 14, 2026
Merged

sergiopaniego merged 7 commits into
mainfrom
fix-small-followups

Conversation

@sergiopaniego

@sergiopaniego sergiopaniego commented Oct 10, 2026 •

Copy link
Copy Markdown
Collaborator

Three small fixes, one commit each.

1. Remove dead openenv_core import fallbacks (maze_env, websearch_env, openapp_env, qed_math_env)

openenv_core is a deprecation shim inside the openenv package that re-exports openenv.core, so falling back to it after openenv.core fails can never help. The envs now import from openenv.core directly, as #1379 did for snake_env. Checked that the models, clients and servers still import both in-repo (PYTHONPATH=src:envs) and standalone (from the env directory, where the env supports it).

2. GitServerClient.execute_git_command breaks quoted arguments

The command was split with str.split(), so commit -m "two words" reached git as -m '"two' 'words"' and failed with pathspec 'words"' did not match. It now uses shlex.split. The new test commits with a two-word quoted message in a tmp repo (HOME pointed at tmp_path) and checks the message.

3. build_model_step leaks a thread per call

Since #1367, every build_model_step call starts a daemon thread with an event loop that never stops. The CLI builds one per run, but a library user building one per episode gains a thread per episode. The loop is now created lazily once and shared by all model steps, so every call still runs on the same long-lived loop and #1367's "Event loop is closed" fix holds (its regression test still passes). The new test calls build_model_step five times and checks that threading.active_count() grows by at most one.

How it was checked

  • New tests fail before the fix and pass after (git: pathspec 'words"', collect: 16 threads vs at most 12).
  • tests/core/test_git_server_client.py, tests/core/test_harness_collect.py, tests/test_cli/test_collect.py, tests/envs/test_openspiel_collect.py, tests/envs/test_maze_environment.py (including the gunicorn server tests), tests/envs/test_websearch_environment.py, tests/envs/test_qed_math_environment.py (excluding TestQEDMathServerIntegration, which needs a running server) all pass.

This PR was prepared with AI assistance.


Note

Low Risk
Changes are import cleanup, safer shell parsing for git, and a shared event loop with existing regression tests; no auth or data-path changes.

Overview
This PR bundles three small fixes across env imports, git tooling, and rollout collection.

Env imports: Several environments (maze_env, openapp_env, websearch_env, qed_math_env) now import from openenv.core only and drop nested try/except fallbacks to openenv_core, which cannot help when openenv.core is missing.

Git client: GitServerClient.execute_git_command parses the command string with shlex.split so quoted arguments (e.g. commit messages with spaces) are passed to git correctly; a regression test covers empty commits with a two-word message.

Collect harness: build_model_step lazily creates one shared background asyncio loop (via @functools.cache) for all model steps instead of starting a new daemon thread on every call, preserving the pooled-async-client fix while avoiding thread leaks when callers build a step per episode.

Reviewed by Cursor Bugbot for commit 916d3a1. Bugbot is set up for automated code reviews on this repo. Configure here.

maze_env, websearch_env, openapp_env and qed_math_env still fall back to
openenv_core when importing from openenv.core fails. openenv_core is a
deprecation shim shipped inside the openenv package that re-exports
openenv.core, so the fallback can only run when openenv.core is already
importable. Import from openenv.core directly, as #1379 did for snake_env.
execute_git_command split the command on whitespace, so a quoted
argument such as commit -m "two words" reached git as two arguments
and the commit failed. Split with shlex.split so quoted arguments stay
intact.
Each build_model_step call started a daemon thread running a new event
loop that never stops, so a library user building a model step per
episode leaked a thread per episode. Start the loop lazily once and
share it across all model steps. Every call still runs on the same
long-lived loop, so pooled async clients keep working (#1367).
@burtenshaw burtenshaw added bug Something isn't working size: medium Medium pull request labels Oct 10, 2026 — with Cursor
@bot-ci-comment

Copy link
Copy Markdown

The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.

Comment thread envs/maze_env/client.py Fixed

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Alignment Review Report

Automated Checks

  • Lint: PASS — uv run usort check / ruff format --check / ruff check are clean on every file this PR touches (src/openenv/core/harness/collect.py, src/openenv/core/tools/git_server_client.py, both new test files, and all 12 envs/* import-fallback files). The repo-wide lint.sh run does report failures, but I verified each one is pre-existing on the merge base (8d3455ab) and untouched by this diff (mostly unrelated README/docstring formatting and two long-standing F401/F821 issues in envs/openapp_env/server/openapp_environment.py from an untouched try: import playwright.sync_api block). Nothing in this PR regresses lint.
  • Debug code: CLEAN — check-debug.sh only flags print()/TODO occurrences in files this PR doesn't touch (src/openenv/auto/*, src/openenv/harbor/*, src/openenv/cli/*). No debug code in the diff.

Open RFCs Context

  • RFC 005 (Agentic Harnesses, In Review) and RFC 006 (Agentic RL Harness Interception, In Review) both treat ModelStep as the fixed generate-hook contract. This PR's collect.py change only caches the event loop build_model_step schedules onto — it does not touch ModelStep's signature or the wrapping/session/capture abstractions those RFCs own, so no conflict.
  • No other Draft/In-Review RFC (000–003, 008, 010–012) touches git tooling, env import shims, or this harness internal, so no further RFC overlap.

Tier 1: Fixes Required

None — mechanical checks are clean for the diff.

Tier 2: Alignment Discussion

Principle Conflicts

None identified. Specifically checked and ruled out:

  • The openenv_core import-fallback removal (maze_env, openapp_env, websearch_env, qed_math_env) is not a breaking change requiring the INVARIANTS.md deprecation process: src/openenv_core/__init__.py imports openenv.core unconditionally at module load, so the removed except ImportError: from openenv_core... branches could never actually execute — they were dead code. The openenv_core shim package itself is untouched and still works exactly as before for any user importing it directly. This mirrors the precedent already set for snake_env in #1379.
  • functools.cache-sharing one event loop across build_model_step calls doesn't change the public ModelStep contract or introduce new concurrency between environment instances — it only fixes a resource leak if the helper is (re)built per episode instead of per run, consistent with the existing "one env = one trajectory" guidance rather than conflicting with it.
  • shlex.split in GitServerClient.execute_git_command is a straightforward correctness fix (quoted args were previously broken by naive .split()) with no interface change.

RFC Conflicts

None identified (see Open RFCs Context above).

Verification performed

  • Ran the full lint pipeline (usort, ruff format --check, ruff check) scoped to every file in the diff — clean.
  • Ran tests/core/test_git_server_client.py and tests/core/test_harness_collect.py — 54/54 passed, including both new tests (test_execute_git_command_keeps_quoted_args, test_repeated_builds_share_one_loop_thread).
  • Ran the full suite (PYTHONPATH=src:envs pytest tests/, excluding the smolagents-dependent module that fails to collect without that optional dep): 3493 passed, 166 skipped, 2 failed. Confirmed both failures (test_protocol_client_state, test_protocol_client_multiple_episodes in tests/envs/test_websockets.py) reproduce identically on the unmodified merge-base commit, so they are pre-existing flakiness/bugs unrelated to this PR.

Summary

  • 0 mechanical issues to fix
  • 0 alignment points for human review
  • 0 RFC conflicts to discuss

This is a clean, well-scoped follow-up PR: a genuine quoting bug fix in GitServerClient, a real thread-leak fix in build_model_step, and dead-code removal of unreachable import fallbacks, each covered by tests. No principle or RFC concerns.

Open in Web View Automation 

Sent by Cursor Automation: Pre-review

@sergiopaniego
sergiopaniego merged commit f4ec8bf into main Oct 14, 2026
15 checks passed
@sergiopaniego
sergiopaniego deleted the fix-small-followups branch October 14, 2026 11:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working size: medium Medium pull request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants