Skip to content

refactor: separate EnvironmentConfig from SLURM allocation - #41

Merged
gregorweiss merged 7 commits into
feat/parsl-simulatefrom
feature/issue-40-environment-config
Aug 12, 2026
Merged

refactor: separate EnvironmentConfig from SLURM allocation#41
gregorweiss merged 7 commits into
feat/parsl-simulatefrom
feature/issue-40-environment-config

Conversation

@gregorweiss

Copy link
Copy Markdown
Collaborator

Closes #40

Separate EnvironmentConfig from SLURM allocation in executor config — structured model replacing the opaque worker_init string, with backward compatibility and TUI refactoring into three visual sections.

Implementation plan posted as a comment below.

@gregorweiss

Copy link
Copy Markdown
Collaborator Author

Implementation Plan

Problem Analysis

The current SlurmExecutorConfig conflates SLURM allocation (cluster infra), execution environment (tool setup), and per-stage tuning into a single flat model. The worker_init field is an opaque string that combines module loading, pixi activation, and arbitrary shell commands — assembled by string concatenation in the TUI and serialized as a blob in YAML. This blocks clean implementation of MPS GPU sharing (issue 10), benchmark sweep output routing (issue 9), and multi-backend workers (issues 21, 22).

Deliverables

  1. EnvironmentConfig model — new file mdfactory/orchestration/environment.py (~120 lines)

    • Structured fields: modules, pixi_manifest, conda_env, venv_path, extra_init
    • compose_worker_init() method producing the shell snippet
    • detect() classmethod for auto-detection (pixi via PIXI_PROJECT_MANIFEST / filesystem, conda via CONDA_PREFIX, venv via VIRTUAL_ENV)
  2. ExecutorConfig.environment field — replaces direct worker_init usage

    • Backward-compatible: if YAML has worker_init but no environment, use string as-is with deprecation warning
    • If environment is present, compose_worker_init() generates the string passed to Parsl
    • to_parsl_config() updated to use environment.compose_worker_init() (or legacy worker_init)
  3. TUI refactored into three visual sections — SLURM Allocation, Execution Environment, Per-Stage Tuning

    • Rich Rule separators between sections
    • Environment section: auto-detection display, module prompts, pixi/conda confirmation
    • GROMACS prompts moved into environment section
    • build workflow skips GROMACS module prompts
  4. YAML format updated — nested environment: section in generated configs

    • save_slurm_config_yaml() emits structured environment: block
    • from_yaml() handles both legacy flat worker_init and new nested format
  5. Tests covering all new behavior

Acceptance Criteria

  • EnvironmentConfig.compose_worker_init() produces correct shell snippets for all combinations (modules only, pixi only, conda only, venv only, modules+pixi+extra_init, empty)
  • EnvironmentConfig.detect() discovers pixi (filesystem + env var), conda (CONDA_PREFIX), venv (VIRTUAL_ENV)
  • Legacy YAML with flat worker_init still loads via from_yaml() — backward compat with deprecation warning logged
  • New YAML with environment: section loads and compose_worker_init() generates correct shell string
  • to_parsl_config() passes the composed worker_init string to Parsl providers (both local and SLURM)
  • TUI wizard shows three clearly separated sections (Rich Rule separators)
  • mdfactory config slurm generates YAML with nested environment: section
  • build workflow (stages=()) skips GROMACS prompts in environment section
  • simulate workflow shows full environment section including module detection
  • All existing tests pass; new tests cover EnvironmentConfig thoroughly

Files to Create or Modify

File Changes
mdfactory/orchestration/environment.py NEWEnvironmentConfig model, compose_worker_init(), detect() classmethod
mdfactory/orchestration/config.py Add environment: EnvironmentConfig field, backward-compat validator for legacy worker_init, update to_parsl_config()
mdfactory/orchestration/tui.py Refactor wizard into 3 sections with Rich Rules; replace _default_worker_init() + _prompt_gromacs_source() with EnvironmentConfig-based flow; remove dead _detect_gromacs_modules (line 56)
mdfactory/orchestration/__init__.py Export EnvironmentConfig
mdfactory/tests/test_orchestration_environment.py NEW — tests for compose_worker_init(), detect(), YAML round-trip
mdfactory/tests/test_orchestration_config.py Add tests for backward-compat worker_init migration, from_yaml() with nested environment
mdfactory/tests/test_orchestration_tui.py Update mocked prompt sequences for new 3-section flow
examples/slurm_executor.yaml Update to new environment: section format
docs/content/docs/user-guide/running-on-hpc.mdx Update YAML examples, explain environment section

Testing Approach

test_orchestration_environment.py (new file):

  • test_compose_worker_init_modules_only — modules list produces module load X; module load Y
  • test_compose_worker_init_pixi — pixi_manifest produces eval "$(pixi shell-hook ...)"
  • test_compose_worker_init_conda — conda_env produces conda activate X
  • test_compose_worker_init_venv — venv_path produces source .../bin/activate
  • test_compose_worker_init_combined — modules + pixi + extra_init joined correctly
  • test_compose_worker_init_empty — all defaults produce empty string
  • test_compose_worker_init_priority — pixi takes precedence over conda/venv
  • test_detect_pixi_from_filesystem — monkeypatch Path.exists to simulate pixi env
  • test_detect_pixi_from_env_var — monkeypatch PIXI_PROJECT_MANIFEST
  • test_detect_conda_from_env — monkeypatch CONDA_PREFIX
  • test_detect_venv_from_env — monkeypatch VIRTUAL_ENV
  • test_detect_nothing — clean env produces empty EnvironmentConfig

test_orchestration_config.py (additions):

  • test_from_yaml_legacy_worker_init — flat worker_init loads into environment.extra_init
  • test_from_yaml_environment_section — nested environment: loads correctly
  • test_from_yaml_both_warns — both present emits deprecation warning
  • test_to_parsl_config_uses_environment — composed string reaches provider.worker_init

test_orchestration_tui.py (updates):

  • Existing tests updated for new prompt sequence (3 sections)
  • New test for environment section prompts

Risks and Open Questions

  1. Backward compatibility complexity — The validator migrating worker_init to EnvironmentConfig must handle arbitrary user strings (not just TUI-generated format). Safest approach: put raw string into extra_init field.
  2. TUI test brittleness — Tests mock .ask.side_effect lists depending on prompt count/order. Refactoring changes the sequence, requiring all side_effect lists to be updated. Mechanical but tedious.
  3. gmx_binary stays on ExecutorConfig — Tool selection (which binary to invoke) is separate from environment setup. No change needed.
  4. MPS is future workMPSConfig included in model definition but TUI prompts deferred to issue 10.
  5. Dead code cleanup — The shadowed _detect_gromacs_modules at line 56 removed as part of this refactor.

Plan created by mach6

- Add EnvironmentConfig model (modules, pixi_manifest, conda_env, venv_path, extra_init)
- compose_worker_init() produces shell snippet from structured fields
- detect() classmethod auto-detects pixi/conda/venv from environment
- Refactor TUI into 3 visual sections with Rich Rule separators
- Remove dead _detect_gromacs_modules (shadowed definition)
- Update docs and example YAML to new environment: section format
@gregorweiss

Copy link
Copy Markdown
Collaborator Author

Progress Update

Implemented the full refactor — replaced worker_init with structured EnvironmentConfig.

Changes

New files:

  • mdfactory/orchestration/environment.pyEnvironmentConfig Pydantic model with compose_worker_init() and detect() classmethod
  • mdfactory/tests/test_orchestration_environment.py — 22 tests (compose variants, detect from pixi/conda/venv, serialization)

Core changes:

  • config.py — Replaced worker_init: str = "" with environment: EnvironmentConfig (non-optional, defaults to empty). Both to_parsl_config() methods call environment.compose_worker_init() directly. No backward compat needed (orchestration module has never been on main).
  • tui.py — Refactored wizard into 3 visual sections with Rich Rule separators (SLURM Allocation / Execution Environment / Per-Stage Tuning). Removed dead shadowed _detect_gromacs_modules. Replaced _prompt_gromacs_source() + _default_worker_init() with _prompt_environment() building a structured EnvironmentConfig.
  • __init__.py — Exports EnvironmentConfig

Tests and docs:

  • Updated test_orchestration_config.py and test_orchestration_tui.py for new API
  • Updated examples/slurm_executor.yaml, running-on-hpc.mdx, workflows.mdx

Verification

  • 2912 tests pass (excluding pre-existing broken test_lock_folder_processes)
  • ruff lint + format clean

Commit: c094534


Progress tracked by mach6

@gregorweiss
gregorweiss marked this pull request as ready for review August 11, 2026 20:18
@gregorweiss

Copy link
Copy Markdown
Collaborator Author

Code Review

Important

1. Unquoted paths in compose_worker_init() shell commands (confidence: 85)
mdfactory/orchestration/environment.py lines 88–95

Two shell snippets embed filesystem paths without shell-quoting:

f'eval "$(pixi shell-hook --manifest-path {self.pixi_manifest} -e default)"'
f"source {self.venv_path}/bin/activate"

A path with spaces breaks both commands silently — workers start but have no Python environment. Jobs then fail with ModuleNotFoundError deep in task logs rather than at submission. Fix: wrap path expansions in single quotes.

2. CONDA_PREFIX detection extracts wrong environment name for base conda (confidence: 85)
mdfactory/orchestration/environment.py lines 140–143

conda_path = Path(conda_prefix)
kwargs["conda_env"] = conda_path.name

When the base environment is active, CONDA_PREFIX=/opt/miniconda3name="miniconda3"conda activate miniconda3 fails. Should use CONDA_DEFAULT_ENV env var which conda sets to the canonical name ("base" for base env).

Suggestions

3. get_stage_config ValueError for invalid override keys is untested (confidence: 95)
mdfactory/orchestration/config.py — The primary guard against invalid stage_overrides keys (e.g. {"EM": {"walltime": "1h"}}) has no test. A regression would silently accept invalid configs.

4. _prompt_gromacs_modules is entirely untested (confidence: 90)
mdfactory/orchestration/tui.py — All integration tests mock _prompt_environment, so _prompt_gromacs_modules (6 branches: PATH short-circuit, module selection, custom, skip) is never exercised.

5. _prompt_environment is mocked everywhere — its own behaviors untested (confidence: 90)
mdfactory/orchestration/tui.py — Key behaviors like stages=() skipping GROMACS prompts, precedence logic, and extra_init stripping are untested.

6. Redundant mutual-exclusivity re-derivation in _prompt_environment (confidence: 95)
mdfactory/orchestration/tui.py line ~550 — The if not env.pixi_manifest else None guards are dead logic since detect() already guarantees mutual exclusivity. Simplify to env.model_copy(update={"modules": modules, "extra_init": extra_init.strip()}).

7. _select_with_custom "Custom…" branch never exercised (confidence: 85)
mdfactory/orchestration/tui.py — The escape-hatch follow-up text prompt is untested.

8. from_yaml ValueError for non-dict YAML is untested (confidence: 85)
mdfactory/orchestration/config.py — Edge case (empty file, bare scalar) is uncovered.

9. configure_and_save_slurm has no test (confidence: 80)
mdfactory/orchestration/tui.py — Public API combining wizard + file-save is untested.

Strengths

  • Clean separation of concerns: EnvironmentConfig is a focused, well-documented Pydantic model
  • detect() classmethod with clear priority chain (pixi > conda > venv)
  • compose_worker_init() is simple, predictable, testable
  • TUI 3-section refactor with Rich Rules gives clear visual structure
  • Comprehensive test coverage for the core model (22 tests in test_orchestration_environment.py)
  • All acceptance criteria from issue 40 are met (confirmed by completeness-checker)
  • No backward-compat baggage — clean break since module was never on main

Agents run: code-reviewer, error-auditor, test-reviewer, completeness-checker, simplifier


Reviewed by mach6

@gregorweiss

Copy link
Copy Markdown
Collaborator Author

Review Assessment

#41 (comment)

Classifications

Finding Classification Reasoning
1. Unquoted paths in compose_worker_init() deferred Factual: True — paths with spaces would break shell commands. Scope: HPC paths effectively never contain spaces. Acceptance criteria ("correct shell snippets for all combinations") refers to field-type combos, not adversarial path content. Not required for safe merge.
2. CONDA_PREFIX wrong name for base conda deferred Factual: True — base env gives "miniconda3" instead of "base". Scope: Primary use case (named envs) works correctly and is tested. HPC users virtually never run in base conda. Edge-case bug, not blocking.
3. get_stage_config ValueError untested deferred Factual: True — no test triggers the invalid-key guard. Scope: Happy paths have 6 tests. Error guard is defensive code; not enumerated in acceptance criteria for this PR.
4. _prompt_gromacs_modules entirely untested deferred Factual: True — 6 branches, none exercised. Scope: TUI prompts tested at integration level via mocked wizard. Internal helper testing not required by authorized scope.
5. _prompt_environment stages=() untested genuine Factual: True — _prompt_environment mocked in all integration tests; stages=() skip logic never exercised. Scope: Plan explicitly states "build workflow (stages=()) skips GROMACS prompts in environment section" as an acceptance criterion. New behavior with explicit AC and no test.
6. Redundant mutual-exclusivity guards nitpick Factual: True — detect() already guarantees exclusivity; guards are dead logic. Scope: Produces correct result either way. Style preference.
7. _select_with_custom Custom branch untested deferred Factual: True. Scope: 4-line utility, trivially correct. Not in acceptance criteria.
8. from_yaml ValueError for non-dict untested deferred Factual: True. Scope: Defensive error path, not enumerated in scope.
9. configure_and_save_slurm no test deferred Factual: True. Scope: Thin wrapper of two tested functions. Not required.

Action Plan

  1. Add test for _prompt_environment(stages=()) skipping GROMACS prompts — The plan explicitly requires "build workflow (stages=()) skips GROMACS prompts." Add a test that calls _prompt_environment(stages=()) with mocked questionary and verifies _prompt_gromacs_modules is NOT called.

Assessment by mach6

@gregorweiss

Copy link
Copy Markdown
Collaborator Author

Progress Update

Fixed review finding 5: added 3 tests for _prompt_environment in test_orchestration_tui.py:

  • test_stages_empty_skips_gromacs_prompts — verifies stages=() (build workflow) does NOT call _prompt_gromacs_modules
  • test_stages_none_calls_gromacs_prompts — verifies stages=None (simulate workflow) DOES prompt for modules
  • test_detected_pixi_flows_through — verifies auto-detected pixi_manifest is preserved in the returned config

All 91 orchestration tests pass, ruff clean.

Commit: ed3e0f6


Progress tracked by mach6

@gregorweiss

Copy link
Copy Markdown
Collaborator Author

Progress Update

Added mdfactory config environment command with global persistence:

  • EnvironmentConfig.save_yaml() / from_yaml() / load_global() — persistence methods on the model, plus get_global_environment_path() utility pointing to ~/.config/mdfactory/environment.yaml
  • configure_and_save_environment() in tui.py — runs the environment wizard and saves to the global config location
  • mdfactory config environment CLI command — interactive wizard to configure execution environment once per machine
  • Auto-loadingExecutorConfig.from_yaml() now loads the global env config when a SLURM YAML has no environment: section; same for default local execution path
  • 11 new tests — save/load roundtrip, empty fields omitted, parent dir creation, missing file, invalid YAML, load_global (no file, existing, corrupt), from_yaml auto-load, explicit environment overrides global

The environment config is "configure once, reuse everywhere" — stable across different SLURM configs that may vary per campaign.

Commit: 9dfa501


Progress tracked by mach6

@gregorweiss gregorweiss self-assigned this Aug 11, 2026
@gregorweiss

Copy link
Copy Markdown
Collaborator Author

Code Review

Important

1. mdfactory config environment cannot update an existing config (confidence: 90)
mdfactory/orchestration/tui.pyconfigure_and_save_environment calls _prompt_environment(stages=None), which bails out immediately if a global config already exists (load_global() is not None → return global_env). After the first run, every subsequent invocation of mdfactory config environment silently re-saves the unchanged config. Users have no way to update modules, switch from conda to pixi, etc., without manually deleting the file. Fix: add an ignore_global parameter to _prompt_environment and pass True from configure_and_save_environment.

2. Global env parse failure silently yields empty worker_init → jobs run with no environment (confidence: 88)
mdfactory/orchestration/environment.py + config.py — When a SLURM YAML omits the environment: section, from_yaml calls load_global(). If the global file exists but is corrupted, load_global() returns None with only a logger.warning. from_yaml treats this as "no file" and proceeds with an empty EnvironmentConfig. Result: Parsl submits jobs with empty worker_init, workers fail with ModuleNotFoundError. The warning is easily missed in dense output. Fix: distinguish "file doesn't exist" (expected) from "file exists but unparseable" (should raise ValueError to fail fast per DESIGN.md rule 6).

3. Conda base-environment detection emits wrong env name (confidence: 85)
mdfactory/orchestration/environment.py lines 147–152 — detect() uses Path(CONDA_PREFIX).name as the env name. In the base environment, CONDA_PREFIX=/home/user/miniconda3 → name="miniconda3" → conda activate miniconda3 fails silently on compute nodes. Fix: check CONDA_DEFAULT_ENV env var, which conda sets to "base" for the base environment.

4. get_stage_config() ValueError for invalid override keys is untested (confidence: 95)
mdfactory/orchestration/config.py — The primary guard against invalid stage_overrides keys (DESIGN.md rule 6: "fail fast on misconfiguration") has zero test coverage. A regression would silently accept invalid configs that propagate to queued jobs.

5. _load_executor_config(None) global-env injection is untested (confidence: 95)
mdfactory/cli.py — When config=None, the function now loads the global env config. This new path (acceptance criterion: "auto-loading from global config") is never exercised because all CLI tests patch _load_executor_config entirely.

6. configure_and_save_environment and config environment CLI command are entirely untested (confidence: 90)
mdfactory/orchestration/tui.py + mdfactory/cli.py — The primary delivery mechanism for global environment persistence has no test coverage at all.

Suggestions

7. Stale PIXI_PROJECT_MANIFEST env var → pixi shell-hook fails silently on compute nodes (confidence: 80)
mdfactory/orchestration/environment.py lines 120–126 — detect() reads PIXI_PROJECT_MANIFEST without verifying the path exists or is accessible from compute nodes. A stale env var produces a worker_init that no-ops silently (eval "" succeeds). Consider confirming the detected path with the user during TUI prompting.

8. display_stage_progress is entirely untested (confidence: 90)
mdfactory/orchestration/progress.pyStageProgressTracker has thorough tests, but display_stage_progress (the Rich live-display function) has none, including the KeyboardInterrupt re-raise path.

9. _prompt_gromacs_modules when GROMACS is already on PATH is untested (confidence: 85)
mdfactory/orchestration/tui.py — The shutil.which("gmx") short-circuit branch (returns [] without prompting) is never exercised in tests.

10. Dead default_factory on _lock and _results in StageProgressTracker (confidence: 95)
mdfactory/orchestration/progress.py lines 53–61 — default_factory=threading.Lock and default_factory=dict allocate objects immediately discarded by __post_init__. Remove the default_factory kwargs since __post_init__ is the sole initializer.

11. Redundant two-step stage_cfgcfg_kwarg with tautological None check (confidence: 90)
mdfactory/orchestration/simulate.py lines 843–848 — get_stage_config() never returns None, so the if stage_cfg is not None check after hasattr is always true. Merge into a single conditional.

12. Redundant mutual-exclusivity guards in _prompt_environment (confidence: 85)
mdfactory/orchestration/tui.py lines 396–403 — The if not env.pixi_manifest else None guards re-implement exclusivity that detect() already guarantees. Simplify to pass-through.

13. progress.py imports a private function from build.py (confidence: 80)
mdfactory/orchestration/progress.py line 138 — from .build import _get_block_status couples two independent modules. Since it's now called from two places, consider moving it to a shared utility.

14. Legacy worker_init backward compat not implemented (confidence: 90)
Issue 40 acceptance criteria require that a YAML with flat worker_init still loads with a deprecation warning. The plan comment says "No backward compat needed (orchestration module has never been on main)." This is a deliberate scope reduction, not an oversight — but the issue criteria should be explicitly updated.

Strengths

  • Clean Pydantic model design: EnvironmentConfig is focused, well-documented, and follows established patterns
  • compose_worker_init() is simple, predictable, and thoroughly tested (14 compose tests)
  • detect() classmethod with clear priority chain (pixi > conda > venv) follows factory method pattern
  • TUI three-section refactor with Rich Rules gives clear visual structure
  • Thread-safe StageProgressTracker with proper terminal-state sentinel set
  • Comprehensive test coverage for new models (335 lines for environment, 142 for progress)
  • All acceptance criteria met (with the noted deliberate backward-compat scope reduction)

Agents run: code-reviewer, error-auditor, test-reviewer, completeness-checker, simplifier


Reviewed by mach6

@gregorweiss

Copy link
Copy Markdown
Collaborator Author

Review Assessment

#41 (comment)

Classifications

Finding Classification Reasoning
1. mdfactory config environment cannot update existing config genuine Factual: Confirmed — configure_and_save_environment() calls _prompt_environment(stages=None) which at line 518 returns immediately if load_global() is not None. Users cannot update without deleting the file. Scope: The plan explicitly delivers this CLI command as the primary global persistence mechanism. A config command that can only set once but never update is broken for its stated purpose. Violates DESIGN.md rule 6.
2. Global env parse failure silently yields empty worker_init genuine Factual: Confirmed — load_global() catches all exceptions and returns None with logger.warning. from_yaml treats None as "no file" and proceeds with empty EnvironmentConfig. Jobs submit with empty worker_init. Scope: DESIGN.md rule 6 explicitly states "fail fast on misconfiguration…should raise immediately…not propagate silently to a queued job." A corrupt config file silently yielding empty worker_init directly violates this rule.
3. Conda base-environment detection emits wrong env name deferred Factual: Confirmed — Path(CONDA_PREFIX).name yields "miniconda3" for base env. Scope: Primary case (named conda envs) works correctly. Base-env edge case is a robustness concern for an unusual scenario. Not required to ship.
4. get_stage_config() ValueError untested genuine Factual: Confirmed — no test exercises the _HONORED_OVERRIDE_KEYS validation guard. Scope: New fail-fast code added by this PR. If it regresses, invalid configs silently propagate to queued jobs. Tests should ship with new testable code.
5. _load_executor_config(None) global-env injection untested genuine Factual: Confirmed — the config is None branch (cli.py lines 210-215) is never exercised; all CLI tests patch _load_executor_config entirely. Scope: New code implementing an explicit plan deliverable ("auto-loading from global config").
6. configure_and_save_environment and CLI command untested genuine Factual: Confirmed — zero test results for these functions. Scope: New user-facing CLI command that is an explicit plan deliverable.
7. Stale PIXI_PROJECT_MANIFEST env var deferred Factual: Partially valid — speculative edge case about HPC filesystem topology, not a code bug. Scope: Not required to ship.
8. display_stage_progress untested deferred Factual: Confirmed — only patched out in simulate tests. Scope: Rich live-display function inherently difficult to unit test. The StageProgressTracker dataclass itself has thorough tests. Not a core correctness concern.
9. _prompt_gromacs_modules PATH short-circuit untested deferred Factual: Confirmed. Scope: Pre-existing function body; the PR only refactored where it is called from. Not new code.
10. Dead default_factory on _lock and _results nitpick Factual: Confirmed — objects created by default_factory are immediately overwritten by __post_init__. Scope: No functional impact. Style preference.
11. Redundant two-step stage_cfg to cfg_kwarg false-positive Factual: The hasattr check handles the case where config is a base ExecutorConfig (no get_stage_config), setting stage_cfg = None. The None check is therefore necessary and correct — not tautological.
12. Redundant mutual-exclusivity guards nitpick Factual: Guards are defensive but not harmful — detect() already guarantees exclusivity. Scope: Stylistic preference; provides defense-in-depth.
13. progress.py imports private function from build.py nitpick Factual: Confirmed cross-module private import. Scope: Both files are in the same package. Common Python pattern. Not a correctness issue.
14. Legacy worker_init backward compat not implemented false-positive Factual: The plan explicitly states "No backward compat needed (orchestration module has never been on main)." Authorized scope decision with justification. Issue criteria should be updated to reflect this.

Action Plan

  1. Fix mdfactory config environment to allow updating existing config — Add ignore_global parameter to _prompt_environment (default False); configure_and_save_environment passes True so the wizard always runs interactively.

  2. Make corrupt global env config fail fast — In load_global(), distinguish "file doesn't exist" (return None) from "file exists but unparseable" (raise ValueError). Prevents silent submission of jobs with empty worker_init.

  3. Add test for get_stage_config() ValueError on invalid override keys — Verify that passing an unhonored key like "walltime" in stage_overrides raises ValueError.

  4. Add test for _load_executor_config(None) global-env injection — Test the config is None branch that loads global env config.

  5. Add test for configure_and_save_environment — Test the wizard-save flow with mocked questionary prompts.


Assessment by mach6

@gregorweiss

Copy link
Copy Markdown
Collaborator Author

Progress Update

Fixed all 5 genuine review findings from the mach6 assessment:

Bug Fixes

  • configure_and_save_environment now allows updating existing config — added ignore_global parameter to _prompt_environment; the dedicated CLI command always runs the interactive wizard regardless of existing saved config
  • Corrupt global env config now fails fastload_global() raises ValueError when the file exists but is unparseable, instead of silently returning None and submitting jobs with empty worker_init

New Tests

  • get_stage_config() ValueError on invalid override keys (2 tests)
  • _load_executor_config(None) global-env injection paths (3 tests: no global, with global, corrupt global)
  • configure_and_save_environment wizard-save flow (3 tests: saves to path, ignores existing config, propagates cancellation)

Verification

  • 122 orchestration tests pass
  • ruff lint + format clean

Commit: e8a974e


Progress tracked by mach6

@gregorweiss

Copy link
Copy Markdown
Collaborator Author

Code Review (re-review after e8a974e)

Fix Verification

All 5 fixes from e8a974e confirmed correct:

  • Fix 1: ignore_global param — clean default-false design, configure_and_save_environment passes True
  • Fix 2: load_global() fail-fast — try/except removed, ValueError propagates through all 3 call sites ✅
  • Fix 3: get_stage_config ValueError tests — 2 tests covering single and multiple bad keys ✅
  • Fix 4: _load_executor_config(None) tests — 3 tests covering no-global, with-global, corrupt-global ✅
  • Fix 5: configure_and_save_environment tests — 3 tests covering save, ignore-existing, cancellation ✅

Suggestions

1. ExecutorConfig.from_yaml() corrupt-YAML guard is untested (confidence: 88)
mdfactory/orchestration/config.py — The if not isinstance(data, dict): raise ValueError guard has no test coverage. EnvironmentConfig.from_yaml has an identical guard that IS tested. Consistency gap.

2. configure_and_save_slurm() has zero test coverage (confidence: 83)
mdfactory/orchestration/tui.py — The analogous configure_and_save_environment received 3 tests in this PR, but configure_and_save_slurm has none.

3. Dead if dry_run: pass block (confidence: 92)
mdfactory/orchestration/simulate.py — The if dry_run: pass is a no-op. The explanatory comment should be a plain comment, not an unreachable conditional.

4. _detect_skip_mode_state single-call helper with duplicated three-way logic (confidence: 85)
mdfactory/orchestration/simulate.py — Called exactly once; its three-way logic is already inlined in the caller's traj_files branch. Fold it in to remove indirection and duplication.

5. _validate_simulation_dir dead in production (confidence: 82)
mdfactory/orchestration/simulate.py — Only appears in test imports. Production path uses _validate_stage_prerequisites and _missing_build_files directly.

6. Sections 2+3 verbatim-duplicated in _configure_with_cluster and _configure_manual (confidence: 85)
mdfactory/orchestration/tui.py — The Execution Environment + Per-Stage Tuning sections are identical 11-line blocks at the end of both wizard paths. Could extract a shared helper.

Strengths

  • All 5 prior genuine findings correctly and completely fixed
  • Error handling is now solid throughout — load_global() fail-fast propagates cleanly through all call sites
  • ignore_global parameter is a clean, minimal design — default False preserves normal wizard behavior
  • 122 tests pass, ruff clean
  • All acceptance criteria fully met

Agents run: code-reviewer, error-auditor, test-reviewer, completeness-checker, simplifier


Reviewed by mach6

@gregorweiss

Copy link
Copy Markdown
Collaborator Author

Review Assessment (re-review after e8a974e)

#41 (comment)

Classifications

Finding Classification Reasoning
1. ExecutorConfig.from_yaml() corrupt-YAML guard untested deferred Factual: True — the guard at config.py:181 has no direct test. Scope: Pre-existing code, not introduced by this PR. The PR added and tested the analogous EnvironmentConfig.from_yaml() guard.
2. configure_and_save_slurm() zero test coverage deferred Factual: True. Scope: Pre-existing function, not added or changed by this PR. The new configure_and_save_environment() was tested.
3. Dead if dry_run: pass block deferred Factual: True — no-op conditional. Scope: Pre-existing code in run_simulations(), not modified by this PR.
4. _detect_skip_mode_state single-call helper deferred Factual: True — called once. Scope: Pre-existing code, not introduced or modified by this PR.
5. _validate_simulation_dir dead in production deferred Factual: Partially — it is tested and serves as a convenience wrapper, though not called in the main production path. Scope: Pre-existing code.
6. Sections 2+3 duplicated in wizard paths deferred Factual: True — identical 11-line blocks. Scope: Per DESIGN.md DRY rule, extraction requires 3+ occurrences. With exactly 2, this is premature per the project's own principles.

Action Plan

Empty — no genuine issues remain. All 5 prior genuine findings are correctly fixed. All 6 new findings are deferred (pre-existing code outside this PR's scope, or below the project's own extraction threshold).


Assessment by mach6

@gregorweiss
gregorweiss merged commit 7e96242 into feat/parsl-simulate Aug 12, 2026
1 check passed
@gregorweiss
gregorweiss deleted the feature/issue-40-environment-config branch August 12, 2026 10:57
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