Private
Public Access
0
0

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:
2026-06-07 17:57:36 -04:00
parent 42071bd4f4
commit 0c7ebf2267
3 changed files with 48 additions and 4 deletions
+31
View File
@@ -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
View File
@@ -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
+4 -1
View File
@@ -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:
"""