fix(models): remove module-level CONFIG_PATH; re-resolve on every call
ROOT CAUSE: src/models.py had `CONFIG_PATH = get_config_path()` at module level. Every test that imported `src.models` and called `save_config()` or `load_config()` wrote/read the repo-root `config.toml` via this cached constant. The path was resolved once at import time, so the SLOP_CONFIG env var (or test fixtures) couldn't redirect reads/writes without reimporting the module. This silently corrupted the user's config.toml on every test run. The diff between runs showed: 'config.toml changed in working copy' — caused by tests, not the user. FIX: remove the module-level constant; call get_config_path() on every read/write call. SLOP_CONFIG (and any test-time set_config_path() helper) now works without reimport. Also: keep my prior commits to this file (reset_layout command in src/commands.py; the RUN_MMA_INTEGRATION skipif in test_mma_step_mode_sim.py) bundled here for a clean atomic fix-pack since the user just fixed the indentation issue I had. Verified: src.models imports cleanly; load_config/save_config work as expected. Tests that import these functions will use whatever SLOP_CONFIG points to (or the repo-root default).
This commit is contained in:
@@ -241,6 +241,37 @@ def hide_all_panels(app: "App") -> None:
|
||||
app.show_windows[name] = False
|
||||
|
||||
|
||||
@registry.register
|
||||
def reset_layout(app: "App") -> None:
|
||||
"""Reset Layout — Restore the default window layout and clear the stale dock-state cache.
|
||||
|
||||
Useful when a previously-saved manualslop_layout.ini references
|
||||
window names that no longer exist (e.g. after a refactor renames
|
||||
windows) and the dock space appears empty / non-recoverable via
|
||||
the Windows menu. Sets every show_windows entry to True and
|
||||
deletes manualslop_layout.ini so hello_imgui regenerates a fresh
|
||||
dock layout on the next frame (and the next process shutdown saves
|
||||
the new layout in place of the stale one). The user will need to
|
||||
restart sloppy.py for the dock layout to fully take effect; the
|
||||
show_windows toggles take effect immediately.
|
||||
"""
|
||||
if hasattr(app, "show_windows") and isinstance(app.show_windows, dict):
|
||||
for name in app.show_windows.keys():
|
||||
app.show_windows[name] = True
|
||||
try:
|
||||
import os
|
||||
layout_paths = [
|
||||
"manualslop_layout.ini",
|
||||
os.path.join("tests", "artifacts", "live_gui_workspace", "manualslop_layout.ini"),
|
||||
]
|
||||
for p in layout_paths:
|
||||
if os.path.exists(p):
|
||||
os.remove(p)
|
||||
if hasattr(app, "ai_status"): app.ai_status = f"layout reset: removed {p}"
|
||||
except Exception as e:
|
||||
if hasattr(app, "ai_status"): app.ai_status = f"layout reset partial: {e}"
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# Layout — Workspace Profiles
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
+13
-3
@@ -145,7 +145,14 @@ DEFAULT_TOOL_CATEGORIES: Dict[str, List[str]] = {
|
||||
"Beads": ["bd_create", "bd_update", "bd_list", "bd_ready"],
|
||||
}
|
||||
|
||||
CONFIG_PATH = get_config_path()
|
||||
# CONFIG_PATH was a module-level constant. REMOVED: it cached the
|
||||
# repo-root config.toml at import time, so any test calling
|
||||
# save_config() or load_config() after import wrote/read the
|
||||
# user's actual config — corrupting the user's settings every test
|
||||
# run. The path is now re-resolved on every call, so the SLOP_CONFIG
|
||||
# env var (or a set_config_path() helper from test fixtures) can
|
||||
# redirect reads/writes to a temp_workspace without reimporting.
|
||||
# See tests/conftest.py:reset_paths for the test-side mechanism.
|
||||
|
||||
#region: Config Utilities
|
||||
|
||||
@@ -160,7 +167,7 @@ def load_config() -> dict[str, Any]:
|
||||
"""
|
||||
[C: src/multi_agent_conductor.py:ConductorEngine.__init__]
|
||||
"""
|
||||
with open(CONFIG_PATH, "rb") as f:
|
||||
with open(get_config_path(), "rb") as f:
|
||||
return tomllib.load(f)
|
||||
|
||||
def save_config(config: dict[str, Any]) -> None:
|
||||
@@ -172,11 +179,14 @@ def save_config(config: dict[str, Any]) -> None:
|
||||
config = _clean_nones(config)
|
||||
sys.stderr.write(f"[DEBUG] Saving config. Theme: {config.get('theme')}\n")
|
||||
sys.stderr.flush()
|
||||
with open(CONFIG_PATH, "wb") as f:
|
||||
with open(get_config_path(), "wb") as f:
|
||||
tomli_w.dump(config, f)
|
||||
|
||||
#region: History Utilities
|
||||
|
||||
|
||||
#region: History Utilities
|
||||
|
||||
def parse_history_entries(history_strings: list[str], roles: list[str]) -> list[dict[str, Any]]:
|
||||
import re
|
||||
from src import thinking_parser
|
||||
|
||||
@@ -21,7 +21,10 @@ def _poll_mma_status(client: api_hook_client.ApiHookClient, timeout: int, condit
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.timeout(300)
|
||||
@pytest.mark.skip(reason="Pre-existing test: integration test that requires a real gemini_cli provider to reach 'Awaiting Approval' state. Skipped in the default suite; run live_gui tests against a working provider to exercise this path. Tracked as pre-existing.")
|
||||
@pytest.mark.skipif(
|
||||
not os.environ.get("RUN_MMA_INTEGRATION"),
|
||||
reason="Integration test that requires a working gemini_cli provider AND the live MMA pipeline to reach 'Awaiting Approval' state. The current mock CLI path in this test does not kick the pipeline out of 'idle' (verified: mma=idle for 60s after btn_mma_plan_epic click). Set RUN_MMA_INTEGRATION=1 to run this test against a real provider.",
|
||||
)
|
||||
def test_mma_step_mode_approval_flow(live_gui) -> None:
|
||||
"""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user