From 0f742b1d5f1aaa1af1e2990f60061e8a63497183 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sat, 6 Jun 2026 02:04:05 -0400 Subject: [PATCH] conductor(workflow): add Indentation-Driven Class Method Visibility pitfall (2026-06-05) --- conductor/workflow.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/conductor/workflow.md b/conductor/workflow.md index 06f76274..6e98ad99 100644 --- a/conductor/workflow.md +++ b/conductor/workflow.md @@ -425,3 +425,22 @@ In particular, watch for: ### Live_gui Test Fragility (Authoring-Side) `live_gui` is a session-scoped fixture. All tests in a session share the same `sloppy.py` subprocess. A test that "passes when run after test X but fails in isolation" is a **fragile test, not a fragile fixture**. The fixture is session-scoped by design; the test must explicitly wait-for-ready, reset state via Hook API, and verify preconditions via `get_value`/`wait_for_event` rather than assuming a "clean" ImGui state from a prior test. See [../docs/guide_testing.md](../docs/guide_testing.md#authoring-robust-live_gui-tests-dont-assume-clean-state) for the 5-rule authoring contract with anti-pattern vs pattern code examples. Bisect failures by running the test both in the full suite and in isolation to distinguish "test needs work" from "real app bug". + + +### Indentation-Driven Class Method Visibility (CRITICAL) + +**The bug:** A class method defined with the right intent (2-space indent) may be parsed as **nested inside the previous function** if indentation is off by even one space. The file "passes" syntactically (imports OK) but the method is **not** on the class. `hasattr(App, 'method_name')` returns `False`. Any production code that calls `app.method_name` falls through to `__getattr__`, which delegates to the Controller (which also doesn't have the method), and a cryptic `AttributeError` is raised at runtime. + +**This bit the project in 2026-06-05** during a cleanup commit. `_capture_workspace_profile` was indented with 3 spaces instead of 2 (drift from re-organizing method placement). The Python parser saw the method as a nested function inside `_apply_snapshot` (the previous method). The App class had 59 methods but no `_capture_workspace_profile`. 3 live_gui tests (test_auto_switch_sim, test_workspace_profiles_restoration, test_undo_redo_lifecycle) failed with cryptic `AttributeError: 'AppController' object has no attribute '_capture_workspace_profile'` deep in the test subprocess. + +**How to detect during TDD:** +- After modifying a class body, walk the AST and verify all expected methods are class-level: + ```bash + uv run python -c "import ast; tree = ast.parse(open('src/gui_2.py').read()); [print(item.name) for n in ast.walk(tree) if isinstance(n, ast.ClassDef) and n.name == 'App' for item in n.body if isinstance(item, ast.FunctionDef)]" + ``` +- The skeleton via `manual-slop_py_get_skeleton` should show the method as a class member. If it's missing, it's nested. + +**How to fix:** Re-indent the affected method to exactly 2-space class level. Use the file_slice tool or PyCharm-style auto-format to verify. Run the failing test to confirm. + +**Prevention:** When reorganizing a class body, run the AST check above immediately after the edit. This catches the issue in <1 second vs. finding it via failing live_gui tests minutes later. +