Skip to content

refactor: Refactor run entrypoint scripts - #51

Merged
chrisjz merged 6 commits into
mainfrom
feature/refactor-run-entrypoint-scripts
Feb 1, 2026
Merged

refactor: Refactor run entrypoint scripts#51
chrisjz merged 6 commits into
mainfrom
feature/refactor-run-entrypoint-scripts

Conversation

@chrisjz

@chrisjz chrisjz commented Feb 1, 2026

Copy link
Copy Markdown
Member

Changes:

  • Refactor the run simulation and run evolution scripts.

Summary by CodeRabbit

  • New Features

    • Deterministic per-episode seed derivation for reproducible runs
    • Interactive interrupt handling to export partial results, metrics and plots during simulations
  • Refactor

    • Centralized brain model setup and environment creation via shared utilities; scripts now use these factories instead of inline implementations
  • Chores

    • Lint config updated to ignore rules for the interrupt handler file

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Feb 1, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds utilities to centralize seeding, brain construction, environment creation, and interrupt handling (exports: derive_episode_seed, setup_brain_model, create_env_from_config, manage_simulation_halt, prompt_interrupt); scripts are updated to use these utils and removed their inline implementations.

Changes

Cohort / File(s) Summary
Utils — Seeding & Exports
packages/quantum-nematode/quantumnematode/utils/seeding.py, packages/quantum-nematode/quantumnematode/utils/__init__.py
Added derive_episode_seed(...) (BLAKE2b-based deterministic per-episode seed) and exported it from the utils package.
Utils — Brain Factory
packages/quantum-nematode/quantumnematode/utils/brain_factory.py
New setup_brain_model(...) factory: validates config types, creates parameter initializer, and instantiates various brain implementations with device/shots/gradient/clip and perf-mgmt wiring.
Utils — Environment Loader
packages/quantum-nematode/quantumnematode/utils/config_loader.py
Added create_env_from_config(...) to build a DynamicForagingEnvironment from EnvironmentConfig, composing sub-config params and forwarding seed, max_body_length, and theme.
Utils — Interrupt Handling
packages/quantum-nematode/quantumnematode/utils/interrupt_handler.py
New manage_simulation_halt(...) and prompt_interrupt() to handle KeyboardInterrupts interactively and optionally emit partial outputs (metrics, CSVs, plots) or print session/circuit details.
Scripts — Evolution & Simulation
scripts/run_evolution.py, scripts/run_simulation.py
Removed inline implementations of _derive_episode_seed, _prompt_interrupt, setup_brain_model, and manage_simulation_halt; scripts now import and use centralized derive_episode_seed, setup_brain_model, create_env_from_config, and prompt_interrupt/manage_simulation_halt. Environment creation flow updated.
Config
pyproject.toml
Added per-file ruff ignores for **/utils/interrupt_handler.py (T201, PLR2004).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I hopped through modules, tidy and spry,

Seeds in my pouch for each run gone by,
Brains assemble at a single gate,
Halts that save plots before it’s too late,
A nibble, a hop — modular delight.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main objective: refactoring the run entrypoint scripts (run_simulation.py and run_evolution.py), which is the primary change throughout the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/refactor-run-entrypoint-scripts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chrisjz
chrisjz marked this pull request as ready for review February 1, 2026 10:09

@coderabbitai coderabbitai 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.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@packages/quantum-nematode/quantumnematode/utils/config_loader.py`:
- Line 4: Update the bare dict annotation used for kwargs to a precise typing
such as dict[str, Any] or Mapping[str, Any] (and import Any/Mapping) so the
signature and uses around the kwargs variable are fully typed; find the
function(s) that declare or accept kwargs (the bare "kwargs" referenced around
lines 819-855) and replace dict with dict[str, Any] or Mapping[str, Any] (or a
specific TypedDict if a known shape exists), updating imports from typing
accordingly.

In `@packages/quantum-nematode/quantumnematode/utils/interrupt_handler.py`:
- Around line 141-142: The error message for invalid choices is wrong—update the
logger.error call that currently says "Please enter a number between 1 and 4."
(the one next to the interrupt choice handling / the else branch that validates
the user's choice and uses logger.error) to reflect the actual valid range 0–2,
e.g. "Invalid choice. Please enter a number between 0 and 2." Ensure the message
is changed where the code validates the variable choice and calls logger.error.

In `@scripts/run_evolution.py`:
- Around line 459-466: Remove the unused Ruff noqa marker by deleting the
trailing comment "# noqa: NPY002" on the np.random.seed(...) call inside the
episode loop; keep the seeding logic as-is (the loop in run_evolution.py that
calls derive_episode_seed, np.random.seed and random.seed) but remove the
unnecessary noqa token so the linter no longer flags an unused suppression.
🧹 Nitpick comments (1)
scripts/run_evolution.py (1)

248-260: Avoid reloading the config on every episode.

evaluate_fitness already loads the simulation config; _create_env_for_evolution re-reads the file on each call, so each episode pays extra I/O and parsing. Consider passing the pre-loaded config or env_config into the helper and reusing it per evaluation.

Comment thread packages/quantum-nematode/quantumnematode/utils/config_loader.py
Comment thread packages/quantum-nematode/quantumnematode/utils/interrupt_handler.py Outdated
Comment thread scripts/run_evolution.py Outdated
Comment on lines +459 to +466
for ep in range(episodes):
# Seed RNGs for reproducibility when base_seed is provided
if base_seed is not None:
episode_seed = _derive_episode_seed(base_seed, gen, candidate_idx, ep)
episode_seed = derive_episode_seed(base_seed, gen, candidate_idx, ep)
np.random.seed(episode_seed) # noqa: NPY002
random.seed(episode_seed)

env = create_env_from_config(config_path)
env = _create_env_for_evolution(config_path)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove the unused Ruff noqa.

Line 463’s # noqa: NPY002 is flagged as unused; drop it to keep lint clean.

🧹 Proposed fix
-            np.random.seed(episode_seed)  # noqa: NPY002
+            np.random.seed(episode_seed)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for ep in range(episodes):
# Seed RNGs for reproducibility when base_seed is provided
if base_seed is not None:
episode_seed = _derive_episode_seed(base_seed, gen, candidate_idx, ep)
episode_seed = derive_episode_seed(base_seed, gen, candidate_idx, ep)
np.random.seed(episode_seed) # noqa: NPY002
random.seed(episode_seed)
env = create_env_from_config(config_path)
env = _create_env_for_evolution(config_path)
for ep in range(episodes):
# Seed RNGs for reproducibility when base_seed is provided
if base_seed is not None:
episode_seed = derive_episode_seed(base_seed, gen, candidate_idx, ep)
np.random.seed(episode_seed)
random.seed(episode_seed)
env = _create_env_for_evolution(config_path)
🧰 Tools
🪛 Ruff (0.14.14)

[warning] 463-463: Unused noqa directive (non-enabled: NPY002)

Remove unused noqa directive

(RUF100)

🤖 Prompt for AI Agents
In `@scripts/run_evolution.py` around lines 459 - 466, Remove the unused Ruff noqa
marker by deleting the trailing comment "# noqa: NPY002" on the
np.random.seed(...) call inside the episode loop; keep the seeding logic as-is
(the loop in run_evolution.py that calls derive_episode_seed, np.random.seed and
random.seed) but remove the unnecessary noqa token so the linter no longer flags
an unused suppression.

@codecov

codecov Bot commented Feb 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 28.57143% with 10 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...um-nematode/quantumnematode/utils/config_loader.py 22.22% 7 Missing ⚠️
.../quantum-nematode/quantumnematode/utils/seeding.py 40.00% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai 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.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
scripts/run_evolution.py (1)

433-452: ⚠️ Potential issue | 🟠 Major

Pass body_length/episode seed into the env factory to avoid behavior drift.
After the refactor, create_env_from_config is called without max_body_length or seed, so SimulationConfig.body_length and the per-episode seed are ignored. This can change agent size and reproducibility.

🔧 Suggested fix
-    for ep in range(episodes):
-        # Seed RNGs for reproducibility when base_seed is provided
-        if base_seed is not None:
-            episode_seed = derive_episode_seed(base_seed, gen, candidate_idx, ep)
-            np.random.seed(episode_seed)  # noqa: NPY002
-            random.seed(episode_seed)
-
-        env = create_env_from_config(env_config)
+    for ep in range(episodes):
+        episode_seed: int | None = None
+        # Seed RNGs for reproducibility when base_seed is provided
+        if base_seed is not None:
+            episode_seed = derive_episode_seed(base_seed, gen, candidate_idx, ep)
+            np.random.seed(episode_seed)  # noqa: NPY002
+            random.seed(episode_seed)
+
+        env = create_env_from_config(
+            env_config,
+            seed=episode_seed,
+            max_body_length=config.body_length,
+        )
🧹 Nitpick comments (2)
packages/quantum-nematode/quantumnematode/utils/config_loader.py (1)

819-859: Switch create_env_from_config docstring to NumPy style.
The new docstring uses Args:; please convert to NumPy Parameters/Returns sections to match the repo standard.

♻️ Example docstring update
-    Args:
-        env_config: Parsed environment configuration.
-        seed: Optional seed for environment RNG.
-        max_body_length: Optional max body length for the agent.
-        theme: Optional rendering theme.
-
-    Returns
-    -------
-        Configured DynamicForagingEnvironment instance.
+    Parameters
+    ----------
+    env_config : EnvironmentConfig
+        Parsed environment configuration.
+    seed : int | None
+        Optional seed for environment RNG.
+    max_body_length : int | None
+        Optional max body length for the agent.
+    theme : Theme | None
+        Optional rendering theme.
+
+    Returns
+    -------
+    DynamicForagingEnvironment
+        Configured DynamicForagingEnvironment instance.
As per coding guidelines, Use NumPy-style docstrings for documentation.
packages/quantum-nematode/quantumnematode/utils/interrupt_handler.py (1)

32-143: Convert new interrupt-handler docstrings to NumPy style.
Both new docstrings use Args:; please switch to NumPy Parameters/Returns sections.

♻️ Example update (apply similarly to both functions)
-    Args:
-        max_steps: Maximum number of steps for the simulation.
-        brain_type: Type of brain architecture used.
-        qubits: Number of qubits used.
-        timestamp: Timestamp for the current session.
-        agent: The simulation agent.
-        all_results: List of results for each run.
-        total_runs_done: Total runs completed so far.
-        tracking_data: Data tracked during the simulation.
-        plot_dir: Directory where plots will be saved.
-        plot_results_fn: Optional callable for plotting results.
+    Parameters
+    ----------
+    max_steps : int
+        Maximum number of steps for the simulation.
+    brain_type : BrainType
+        Type of brain architecture used.
+    qubits : int
+        Number of qubits used.
+    timestamp : str
+        Timestamp for the current session.
+    agent : QuantumNematodeAgent
+        The simulation agent.
+    all_results : list[SimulationResult]
+        List of results for each run.
+    total_runs_done : int
+        Total runs completed so far.
+    tracking_data : TrackingData
+        Data tracked during the simulation.
+    plot_dir : Path
+        Directory where plots will be saved.
+    plot_results_fn : Callable[..., Any] | None
+        Optional callable for plotting results.
As per coding guidelines, Use NumPy-style docstrings for documentation.

Also applies to: 145-167

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/quantum-nematode/quantumnematode/utils/interrupt_handler.py`:
- Around line 84-90: The input() call in interrupt_handler.py that reads into
the variable choice can raise EOFError in non-interactive environments and
currently crashes the halt flow; add an except EOFError handler (alongside the
existing KeyboardInterrupt/ValueError handlers) that treats EOF as an exit
signal — e.g., log/handle via logger (similar to KeyboardInterrupt handling) and
break out or set choice to the exit code so the halt menu cleanly exits instead
of propagating the exception.

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