Private
Public Access
0
0

Merge remote-tracking branch 'origin/master' into tier2/post_module_taxonomy_de_cruft_20260627

This commit is contained in:
2026-06-29 14:12:51 -04:00
6 changed files with 51320 additions and 0 deletions
@@ -0,0 +1,110 @@
{
"track_id": "default_layout_install_20260629",
"name": "Default Layout Install + Hardcoded Path Cleanup + layouts/ Stack",
"status": "active",
"branch": "tier2/post_module_taxonomy_de_cruft_20260627",
"created": "2026-06-29",
"owner": "Tier 1 (initialized); implementation delegated to Tier 2/3.",
"blocked_by": [],
"blocks": [],
"scope": {
"new_files": [
"layouts/default.ini",
"src/layouts.py",
"tests/test_default_layout_install.py",
"tests/test_reset_layout.py"
],
"modified_files": [
"src/paths.py (add `layouts: Path` field + SLOP_GLOBAL_LAYOUTS env override + get_layouts_dir() accessor, mirror themes pattern at line 60/83/150/210-216)",
"src/gui_2.py (App._post_init install hook + drain helper `_install_default_layout_if_empty_result`, mirror the existing `_post_init_callback_result` and `_diag_layout_state_ini_text_result` drain pattern at line 1448+)",
"src/commands.py (drop hardcoded tests/artifacts/... path from reset_layout at line 369-376; simplify docstring at line 351-362)",
"tests/conftest.py:709 (path update from tests/artifacts/manualslop_layout_default.ini to layouts/default.ini)",
"conductor/tracks.md (add row at end of Active Tracks)",
"conductor/chronology.md (prepend row)"
],
"deleted_files": [],
"relocated_files": [
"tests/artifacts/manualslop_layout_default.ini -> layouts/default.ini (git mv preserves history; same content; new parallel-to-themes/ home at repo root per user directive 2026-06-29)"
]
},
"estimated_effort": {
"method": "scope (per workflow.md Tier 1 Track Initialization Rules. NO day estimates.)",
"phase_1": "10 tasks: 1 audit + 1 git mv + 1 conftest path update + 4 src/paths.py layouts-field edits + 1 src/layouts.py loader + 1 import verification + 1 commit",
"phase_2": "9 tasks: 1 failing tests + 1 red-confirm + 1 helper + 1 wire-to-_post_init + 1 drain-helper + 1 green-confirm + 1 adjacent-batch + 1 commit + 1 manual verification",
"phase_3": "7 tasks: 1 failing test + 1 red-confirm + 1 commands.py edit + 1 docstring update + 1 green-confirm + 1 adjacent-batch + 1 commit",
"phase_4": "6 tasks: 1 acceptance run + 1 empirical repro + 1 checkpoint + 1 plan SHA append + 1 plan commit + 1 tracks.md row"
},
"verification_criteria": [
"G1: when cwd/manualslop_layout.ini is missing or <1000 bytes or has 0 [Window][ entries, App._post_init installs layouts/default.ini (resolved via src/layouts.py + src/paths.py:get_layouts_dir()) to cwd/manualslop_layout.ini BEFORE immapp.run; log line `[GUI] installed default layout: <src> -> <dst>` is emitted",
"G2: after install, the merged show_windows state has the 8 default-true windows (Project Settings, Files & Media, AI Settings, Discussion Hub, Operations Hub, Theme, Log Management, Diagnostics) set to True even if config.toml previously pinned them to False",
"G3: src/commands.py:reset_layout has only 1 path in layout_paths list (cwd-relative); the tests/artifacts/live_gui_workspace/manualslop_layout.ini reference is gone (verified via inspect.getsource assertion in tests/test_reset_layout.py)",
"G4: tests/test_default_layout_install.py exists and has 3+ tests, all passing: test_default_layout_installed_when_ini_missing, test_default_layout_installed_when_ini_empty, test_default_layout_NOT_installed_when_layout_present",
"G5: layouts/default.ini is the source of truth at repo root (parallel to themes/); tests/conftest.py:709 reads from the new path; the old tests/artifacts/manualslop_layout_default.ini is gone (git mv relocated it)",
"G6: src/paths.py declares a `layouts: Path` field (mirror of themes line 60); resolves layouts = root_dir / 'layouts' (mirror line 83); supports SLOP_GLOBAL_LAYOUTS env + config-file override (mirror line 150); exposes get_layouts_dir() accessor (mirror line 210-216)",
"G7: src/layouts.py exists with LayoutFile @dataclass(frozen=True, slots=True) + load_layouts_from_dir(path, scope) + load_layouts_from_disk() consumer (mirror src/theme_models.py:181-225 + src/theme_2.py:340-346; uses Result[T] per data-oriented convention)",
"G8: tests/conftest.py:709 reads from layouts/default.ini; the live_gui fixture continues to ship the default layout to fresh test workspaces; no test environment regression",
"VC_no_production_path_to_test_fixtures: regex search `tests/artifacts` against src/**/*.py returns 0 matches (the prior false positive at src/commands.py:371 is gone)",
"VC_no_configs_in_src: regex search `\\.ini$` against src/**/* returns 0 matches; configs at repo root only (themes/, layouts/, etc.)"
],
"regressions_and_pre_existing_failures": [],
"pre_existing_failures_remaining": [],
"deferred_to_followup_tracks": [
{
"title": "panel_defs_fleury_migration",
"description": "Migrate the ~40 imperative render_x functions and `_render_window_if_open(name, lambda: render_x(app))` call sites in src/gui_2.py into declarative PanelDef records (name, render_callable, dock_target, default_visible, pops_out) per Ryan Fleury's raddbg 'type view' / 'lens' pattern (talk transcripts at docs/transcripts/rcJwvx2CTZY_ryan_fleury_raddbg_codebase_intro.json and docs/transcripts/_9_bK_WjuYY_ryan_fleury_raddbg_walkthrough.json). The render loop becomes `for panel in PANELS: if app.show_windows.get(panel.name): panel.render(app)`. Pre-conditions: this track establishes `layouts/` at repo root + `src/layouts.py` as the typed loader so the future migration has somewhere to land.",
"track_status": "not yet initialized; deferred per user directive 2026-06-29 ('I don't need to full on convert the gui definitions in the codebase to this way of defining them but just something to keep in mind')"
},
{
"title": "test_engine_integration_20260627 (separate ongoing track)",
"description": "Bridge the imgui test engine so visual regression can verify 'panels are visible' rather than relying on the INI-content proxy this track uses. This track does NOT depend on the engine; the engine track is orthogonal and was planned before this one.",
"track_status": "active (separate track; not blocked by this one)"
},
{
"title": "Visual-regression coverage of empty-INI recovery",
"description": "After test_engine_integration ships, replace the INI-content assertion (G4) with `ctx.capture_screenshot_window('Project Settings')` + baseline PNG diff. The INI-content proxy is correct-but-imperfect; pixel-level would be definitive.",
"track_status": "not yet initialized; follows test_engine_integration Track 3"
},
{
"title": "Multiple bundled layouts",
"description": "After the default layout lands, optionally add `layouts/compact.ini` (small-screen), `layouts/wide.ini` (wide-screen), etc. so users can pick via WorkspaceProfile. Defer until user asks.",
"track_status": "not yet initialized; opportunistic follow-up"
}
],
"risk_register": [
{
"id": "R1",
"description": "Install runs in _post_init (main thread) BEFORE immapp.run reads the INI; if HelloImGui caches the INI filename and resolves it on a different thread, the install may be too late",
"likelihood": "low",
"impact": "install runs but panels still invisible on first render",
"mitigation": "_post_init is the canonical post-init callback wired in src/gui_2.py:685-687; it runs synchronously before the GL/window loop starts. ImGui reads the INI inside immapp.run() during startup. Order is deterministic. Empirical verification via Task 2.9 (user launches sloppy.py standalone with deleted INI; confirms panels visible)."
},
{
"id": "R2",
"description": "shutil.copy2 overwrites a user-customized INI silently; users who intentionally crafted a tiny stub INI to suppress dock saves lose their work",
"likelihood": "low",
"impact": "data loss for power users",
"mitigation": "The empty-INI heuristic is 'file missing OR size < 1000 bytes OR zero [Window][ entries'. Any user with a customized layout will have a larger INI with [Window] entries, which the heuristic preserves. Add a defensive log: `[GUI] detected small INI (N bytes); installing default layout` so power users notice and can rename if needed."
},
{
"id": "R3",
"description": "layouts/default.ini is not in the wheel (git mv's content is fine but a future wheel-build pipeline might exclude it)",
"likelihood": "low",
"impact": "RuntimeError or FileNotFoundError on first launch for end users",
"mitigation": "src/layouts.py catches FileNotFoundError and drains to _startup_timeline_errors. The themes/ pattern at src/theme_2.py:340-346 already handles this precedent. Pre-flight check via Task 4.1 (acceptance run from a fresh wheel-less dev install) catches this."
},
{
"id": "R4",
"description": "Default-true windows in the bundled INI diverge from _default_windows in src/app_controller.py:2086-2108 (e.g., a window renamed but only one of the two got updated)",
"likelihood": "medium",
"impact": "visually inconsistent — some panels docked, some not",
"mitigation": "The bundled INI is intentionally narrower than _default_windows (it omits MMA Dashboard, Task DAG, Tier 1-4, Message, Tool Calls, Text Viewer, etc. — those start hidden per user preference 'I don't want mma to be visible by default' documented at tests/artifacts/manualslop_layout_default.ini:20-22). The convergence assertion is in Task 4.1: 7+ of 9 default-true windows must appear in the saved INI."
},
{
"id": "R5",
"description": "src/layouts.py is a new file; per the file-naming HARD RULE in AGENTS.md ('New src/<thing>.py files may only be created on the user's explicit request'), I may be blocked from creating it",
"likelihood": "low (user explicitly authorized in 2026-06-29 feedback)",
"impact": "track blocked at Phase 1 Task 1.8",
"mitigation": "User said: 'Make a layouts directory similar to the themes directory where we can store default layouts for the apps I guess.' This is explicit authorization for the parallel pattern. src/layouts.py mirrors src/theme_2.py/src/theme_models.py exactly."
}
]
}
@@ -0,0 +1,161 @@
## Phase 1: Move default layout + create layouts/ stack (parallel to themes/)
Focus: relocate `tests/artifacts/manualslop_layout_default.ini` to `layouts/default.ini` at repo root; add the parallel `src/paths.py` field, `get_layouts_dir()` accessor, and `src/layouts.py` loader module — exactly the themes pattern (`themes/` + `src/path.py:60,83,150` + `src/theme_models.py` + `src/theme_2.py`).
- [ ] Task 1.1: Verify bundled layout content + themes pattern baseline
- WHERE: `tests/artifacts/manualslop_layout_default.ini` (109 lines), `src/paths.py:60,83,150,210-216`, `src/theme_models.py:181-225`, `src/theme_2.py:340-346`, `themes/` at repo root
- WHAT: confirm files exist with the expected sizes and that the themes pattern is the canonical reference
- HOW: `git log --oneline -- tests/artifacts/manualslop_layout_default.ini` for provenance; `Get-Content src/paths.py | Select-String -Pattern "themes\s*[:=]|themes\s*=|root_dir/"` to map the path-resolution shape
- SAFETY: pure read; no behavior change
- [ ] Task 1.2: `git mv` asset to new home
- WHERE: `tests/artifacts/manualslop_layout_default.ini``layouts/default.ini` (new dir at repo root, parallel to `themes/`)
- WHAT: `git mv tests/artifacts/manualslop_layout_default.ini layouts/default.ini`
- HOW: PowerShell `git mv` preserves history; verify with `git status` after
- SAFETY: file rename, no content change; `layouts/` is gitignored? verify — `grep -i "layouts" .gitignore` should return nothing (or only `tests/artifacts/` excluding layouts/)
- [ ] Task 1.3: Update `tests/conftest.py:709` to read from `layouts/`
- WHERE: `tests/conftest.py:709``_default_layout_src = project_root / "tests" / "artifacts" / "manualslop_layout_default.ini"`
- WHAT: change to `_default_layout_src = project_root / "layouts" / "default.ini"`
- HOW: `manual-slop_edit_file`; preserve 1-space indentation per `conductor/code_styleguides/python.md`
- SAFETY: no semantic change to test behavior; same bundled content, new path
- [ ] Task 1.4: Add `layouts` field to `src/paths.py` config dataclass (mirror themes)
- WHERE: `src/paths.py:60` (`themes: Path = ...`) — add a `layouts: Path = ...` field right after
- WHAT: add the field declaration matching the `themes` shape exactly
- HOW: `manual-slop_edit_file`; 1-space indent
- SAFETY: additive — does not change existing fields
- [ ] Task 1.5: Resolve `layouts` default in `src/paths.py` (mirror themes)
- WHERE: `src/paths.py:83` (`themes = root_dir / "themes",`) — add `layouts = root_dir / "layouts",` immediately below
- WHAT: resolve the default path in the `initialize_paths`-style function
- HOW: `manual-slop_edit_file`; ensure the same closure/call-site shape as themes
- SAFETY: additive; existing themes path unchanged
- [ ] Task 1.6: Add `SLOP_GLOBAL_LAYOUTS` env + config override (mirror themes)
- WHERE: `src/paths.py:150` — add `_resolve_path("SLOP_GLOBAL_LAYOUTS", "layouts", root_dir / "layouts", config_path)` line in the same call shape
- WHAT: register the env var + config-file override for `layouts`, parallel to themes
- HOW: `manual-slop_edit_file`; exact-string preserve the existing `_resolve_path` call for themes
- SAFETY: additive; new env var only
- [ ] Task 1.7: Add `get_layouts_dir()` accessor to `src/paths.py` (mirror themes)
- WHERE: `src/paths.py:210-216` — add 2 functions (`get_layouts_dir() -> Path` + `get_layouts_project_config_path() -> Path` if themes has it) right after
- WHAT: accessor functions
- HOW: `manual-slop_edit_file`; preserve docstring format
- SAFETY: additive
- [ ] Task 1.8: Create `src/layouts.py` loader module (mirror `src/theme_models.py` + `src/theme_2.py`)
- WHERE: new file `src/layouts.py`
- WHAT: define `LayoutFile` `@dataclass(frozen=True, slots=True)` with `(name: str, raw_text: str, source_path: Path, scope: str)` fields; define `load_layouts_from_dir(path: Path, scope: str) -> dict[str, LayoutFile]` and `load_layouts_from_file(path: Path, scope: str) -> dict[str, LayoutFile]`; define `load_layouts_from_disk() -> None` that calls both with global + project paths; wrap parse errors in `Result` per `conductor/code_styleguides/error_handling.md`
- HOW: model after `src/theme_models.py:181-225` (`load_themes_from_dir`, `load_themes_from_toml`) + `src/theme_2.py:340-346` (`load_themes_from_disk`)
- SAFETY: new file, no existing code modification; uses `from __future__ import annotations` + `@dataclass(frozen=True, slots=True)` per `conductor/code_styleguides/data_oriented_design.md` §8.5
- [ ] Task 1.9: Add `src/layouts.py` to `tests/test_gui2_layout.py`-adjacent test inventory if present; for now, just verify import works
- WHERE: `tests/`
- WHAT: `uv run python -c "from src.layouts import load_layouts_from_disk; print(load_layouts_from_disk())"` to verify the module imports and returns a dict (empty by default since the test cwd has no `layouts/`)
- HOW: direct Python invocation
- SAFETY: pure inspection
- [ ] Task 1.10: Commit phase 1 with git note
- WHAT: `chore(layouts): introduce layouts/ directory + src/layouts.py (themes pattern); relocate default layout asset`
- HOW: standard atomic commit per `conductor/workflow.md` §Task Workflow; attach a 3-line git note explaining: relocation from tests/artifacts; parallel to themes; src/layouts.py mirrors src/theme_models.py + src/theme_2.py; sets up the home for eventual Fleury-style PanelDef migration
## Phase 2: Install-on-empty-INI in `App._post_init`
Focus: ship `layouts/default.ini` to `cwd/manualslop_layout.ini` when the file is missing/empty/small, before `immapp.run(...)` reads it.
- [ ] Task 2.1: Write failing test for install behavior
- WHERE: new file `tests/test_default_layout_install.py`
- WHAT: red phase — 3 tests:
1. `test_default_layout_installed_when_ini_missing``os.remove(cwd/manualslop_layout.ini)` before launch; `subprocess.Popen(sloppy_args, cwd=temp_workspace)`; wait ≥ 5s; assert `manualslop_layout.ini` exists with `[Window][Project Settings]` entry + a non-empty `DockId=` line
2. `test_default_layout_installed_when_ini_empty` — write a 5-byte stub INI before launch; same assertions as (1)
3. `test_default_layout_NOT_installed_when_layout_present` — pre-write a custom `[Window][CustomPanel]` INI; assert the custom panel survives (no overwrite)
- HOW: each test spawns the app via `subprocess.Popen(["uv", "run", "python", "-u", "sloppy.py", "--enable-test-hooks"], cwd=temp_workspace, stdout=log_file, stderr=log_file, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP)` (mirrors the conftest at line 792), waits 5-8s, terminates via `kill_process_tree()` (per the conftest pattern at line 853), then asserts on the saved INI
- SAFETY: tests MUST NOT touch the repo-root `manualslop_layout.ini`; each test uses its own cwd (per `conductor/code_styleguides/workspace_paths.md`); temp workspace path = `Path("tests/artifacts/_default_layout_install_<pid>")`
- [ ] Task 2.2: Run phase 2.1 tests; confirm RED (fails for the right reason)
- WHERE: `tests/test_default_layout_install.py`
- HOW: `uv run pytest tests/test_default_layout_install.py -v --tb=short --timeout=120`
- Expected: 3 tests fail because no install logic exists yet; the temp-workspace INI is empty or absent post-launch
- [ ] Task 2.3: Implement `_install_default_layout_if_empty` helper
- WHERE: new module-level function `_install_default_layout_if_empty(src_ini: Path, dst_ini: Path) -> Result[bool]` near `_diag_layout_state` (`src/gui_2.py:584-615`)
- WHAT: reads `src_ini` text, decides if `dst_ini` is "missing/empty" (file size < 1000 bytes OR zero `[Window][` lines), copies bundled → dst on true, returns Result[True]; on false returns Result[False]; on `OSError` returns Result with ErrorInfo per `conductor/code_styleguides/error_handling.md`
- HOW: `shutil.copy2` for atomic copy; `sys.stderr.write(f"[GUI] installed default layout: {src_ini} -> {dst_ini}\n")` for the user-visible log
- SAFETY: thread-safe (no shared state); pure file I/O; 1-space indentation per project rule
- [ ] Task 2.4: Wire the helper into `App._post_init`
- WHERE: `src/gui_2.py:570-582` (`App._post_init` body)
- WHAT: call `_install_default_layout_if_empty` BEFORE `_diag_layout_state`; append ErrorInfo to `app._startup_timeline_errors` if `not result.ok`
- HOW: `install_result = _install_default_layout_if_empty_result(app, src_path, dst_path)`; if not ok, drain via `_startup_timeline_errors` per the existing pattern at line 580-582
- SAFETY: `_post_init` runs on the main thread (HelloImGui callback), no race
- [ ] Task 2.5: Add drain helper `_install_default_layout_if_empty_result`
- WHERE: `src/gui_2.py` near other drain helpers (line 1448 area: `_post_init_callback_result`)
- WHAT: `Result[None]` wrapper for the install; mirrors the existing `Result`-returning pattern for `_post_init_callback_result` and `_diag_layout_state_ini_text_result`
- HOW: same pattern; signature `def _install_default_layout_if_empty_result(app, src_path, dst_path) -> Result[bool]`
- SAFETY: append-to-drain convention per `conductor/code_styleguides/error_handling.md`
- [ ] Task 2.6: Verify phase 2.1 tests now pass
- WHERE: `tests/test_default_layout_install.py`
- HOW: `uv run pytest tests/test_default_layout_install.py -v --tb=short --timeout=120`
- Expected: all 3 pass; the post-launch INI has 7+ `[Window][X]` entries
- [ ] Task 2.7: Run adjacent test batch (`tests/test_gui*.py`) to confirm no regression
- WHERE: `tests/test_gui2_layout.py`, `tests/test_gui_diagnostics.py`, `tests/test_layout_reorganization.py`
- HOW: `uv run python scripts/run_tests_batched.py --tier test_gui*` (per `conductor/workflow.md` §"Tier 2 Autonomous Sandbox" — use the batched runner, never raw pytest for batched verification)
- Expected: prior batch_green preserved; no _post_init regressions
- [ ] Task 2.8: Commit phase 2 with git note
- WHAT: `fix(gui): install default layout when cwd/manualslop_layout.ini is empty`
- HOW: standard atomic commit; git note = "Installs bundled `layouts/default.ini` (resolved via the new src/layouts.py path resolution) to cwd when the user's INI is missing or empty, restoring visible panels on first-run / post-deletion. Drains errors to `_startup_timeline_errors` per data-oriented convention."
- [ ] Task 2.9: User Manual Verification
- PAUSE; await user `yes` after deleting `manualslop_layout.ini` and launching `sloppy.py` standalone — confirm panels are visible
## Phase 3: Remove hardcoded test-fixture path from production code
Focus: `src/commands.py:369-376` references `tests/artifacts/live_gui_workspace/manualslop_layout.ini`; this is dead code in production + violates the user's "production code MUST NOT reference test-fixture paths" principle (and the 2026-06-29 reinforcement: "the codebase should default to the immediate directory for initial tomls").
- [ ] Task 3.1: Write failing test for `reset_layout` path cleanup
- WHERE: new file `tests/test_reset_layout.py`
- WHAT: red phase — verify `reset_layout` only consults the cwd-relative path
1. `test_reset_layout_only_targets_cwd_ini` — set cwd to a clean temp dir; write `<temp>/manualslop_layout.ini`; create `<temp>/tests/artifacts/live_gui_workspace/manualslop_layout.ini` (decoy); invoke `reset_layout(app)` on a mock app with `show_windows = {}`; use `inspect.getsource(commands.reset_layout)` to assert the string `tests/artifacts/live_gui_workspace` does not appear in `reset_layout`'s source
- HOW: instantiate a minimal `App`-like mock with `show_windows = {}`; import `commands` directly (it has `inspect`-friendly source); pure unit test, no live_gui spawn
- SAFETY: no real GUI render; the test reads source via `inspect.getsource()`
- [ ] Task 3.2: Run phase 3.1 tests; confirm RED
- HOW: `uv run pytest tests/test_reset_layout.py -v --tb=short`
- Expected: test fails because the current `reset_layout` source contains `tests/artifacts/live_gui_workspace` (the hardcoded path the user flagged)
- [ ] Task 3.3: Remove the hardcoded path from `commands.reset_layout`
- WHERE: `src/commands.py:369-376`
- WHAT: `layout_paths = ["manualslop_layout.ini"]` (drop the `os.path.join("tests", ...)` line)
- HOW: `manual-slop_edit_file` with `old_string` containing both `layout_paths = [` and the `os.path.join(...)` line; replace with `layout_paths = ["manualslop_layout.ini"]`
- SAFETY: shrinks the function; no behavior change for end users (cwd-relative was the only functional path)
- [ ] Task 3.4: Update `commands.reset_layout` docstring
- WHERE: `src/commands.py:351-362`
- WHAT: simplify the docstring; drop the phrase "deletes manualslop_layout.ini so hello_imgui regenerates a fresh" if no longer accurate
- HOW: minimal edit via `manual-slop_edit_file`
- SAFETY: docstring only, no behavior change
- [ ] Task 3.5: Verify phase 3.1 tests now pass
- HOW: `uv run pytest tests/test_reset_layout.py -v --tb=short`
- Expected: 1 test passes; the `inspect.getsource` assertion holds
- [ ] Task 3.6: Run adjacent test_batch (`tests/test_commands*.py`)
- HOW: `uv run python scripts/run_tests_batched.py --filter test_commands*`
- Expected: no regression
- [ ] Task 3.7: Commit phase 3 with git note
- WHAT: `chore(commands): remove dead test-fixture path from reset_layout`
- HOW: standard atomic commit; git note = "Reset_layout referenced `tests/artifacts/live_gui_workspace/manualslop_layout.ini`, dead code in production. Removed per user directive 2026-06-29: production code must default to the immediate directory."
## Phase 4: Verification
Focus: full-batch confirmation; per-target test runs; cross-reference the original bug report.
- [ ] Task 4.1: Confirm spec acceptance criteria via test execution
- WHERE: `tests/test_default_layout_install.py`, `tests/test_reset_layout.py`, `tests/test_gui*.py`, `tests/test_commands*.py`
- HOW: `uv run python scripts/run_tests_batched.py --filter "test_default_layout_install|test_reset_layout|test_gui2_layout|test_gui_diagnostics|test_layout_reorganization|test_commands"`
- Acceptance:
- G1 (install on empty INI) — `test_default_layout_installed_when_ini_missing` passes
- G2 (overrides cleared on install) — `test_default_layout_installed_when_ini_empty` passes
- G3 (`reset_layout` path cleanup) — `test_reset_layout_only_targets_cwd_ini` passes
- G4 (regression test for visibility-after-empty) — all 3 `test_default_layout_install` tests pass
- G5 / G6 / G7 (layouts/ stack) — `tests/conftest.py:709` reads from new path; live_gui fixture unaffected; `src/layouts.py` importable
- G8 (conftest path update) — `tests/conftest.py:709` reads from `layouts/default.ini`
- [ ] Task 4.2: Empirical reproduction of the original bug
- WHERE: production cwd (no test harness)
- HOW: `Remove-Item manualslop_layout.ini -ErrorAction SilentlyContinue`; `uv run python sloppy.py`; observe via screenshot or VNC that Project Settings, Files & Media, AI Settings, Discussion Hub, Operations Hub, Theme, Log Management, Diagnostics are all visible
- SAFETY: requires user confirmation; this is the manual verification step per `conductor/workflow.md` §"Phase Completion Verification"
- [ ] Task 4.3: Checkpoint commit + verification git note
- WHAT: `conductor(checkpoint): end of Phase 4 (default_layout_install_20260629 complete)`
- HOW: empty commit allowed per `conductor/workflow.md` §"Phase Completion Verification"; attach a long-form verification report as git note documenting the 1 asset relocated (`tests/artifacts/manualslop_layout_default.ini``layouts/default.ini`), 2 new files (`layouts/default.ini`, `src/layouts.py`), 1 src command file modified (`commands.reset_layout`), 1 paths file modified (`src/paths.py` adds `layouts` field), 1 conftest updated (`tests/conftest.py:709`), 3 test files added (`tests/test_default_layout_install.py`, `tests/test_reset_layout.py`, etc.), and the empirical reproduction result
- [ ] Task 4.4: Append phase checkpoint + completion SHAs to `plan.md`
- WHERE: this file
- WHAT: append `[checkpoint: <7-char SHA>]` after each phase header + `[track complete: <7-char SHA>]` at end
- [ ] Task 4.5: Commit final plan update
- WHAT: `conductor(plan): mark default_layout_install_20260629 phases 1-4 complete`
- [ ] Task 4.6: Add row to `conductor/tracks.md`
- WHERE: `conductor/tracks.md` — Active Tracks table
- WHAT: add a row for `default_layout_install_20260629` with status "shipped 2026-06-29" after Phase 4 completes
- HOW: insert a new row following the table conventions; commit in the same Phase 4 commit batch
@@ -0,0 +1,145 @@
# Track Specification: Default Layout Install + Hardcoded Path Cleanup
## Overview
Manual Slop's GUI panels become invisible at startup whenever `manualslop_layout.ini` is missing, empty, or refers to window names that don't exist in the current build. The root cause is structural: `imgui.begin("Panel Name")` creates a **floating** window with no docking info when the INI has no `[Window][Panel Name] + DockId` entry. Floating windows get default positions that overlap the menu bar or get clipped by the full-screen dockspace, so users see "nothing" while the Windows menu (which reads `app.show_windows`) still shows the panels as "checked."
The pre-existing workaround in `tests/conftest.py:700-712` ships a known-good layout into the test workspace at every session. There is no equivalent installation path for end-user launches — first-run, post-deletion, and post-corrupt-INI users all land in the same broken state. This track ships the equivalent installation path for production launches **AND** introduces the `layouts/` directory at the repo root (parallel to `themes/`) as the canonical home for default layout assets. It also removes a hardcoded `tests/artifacts/...` path that escaped into `src/commands.py`.
**Two patterns established by this track:**
1. **`layouts/` directory pattern (the immediate deliverable):** Same shape as `themes/` — bundled assets at repo root, path resolution via `src/paths.py`, loaders in a parallel `src/` module. Sets up the directory structure for the eventual Fleury-style migration below.
2. **Fleury "type view" / "lens" pattern (the eventual normalization target, NOT in this track):** The user's stated long-term direction is to define GUI panels as declarative "constructs" — data tables of `(panel_name, render_callable, dock_target)` tuples that the renderer iterates per-frame, similar to how Ryan Fleury defines **type views** ("lenses in the code, but views to the user") in the rad debugger to say "if you have this type, just do that automatically for me" (verified from the rad debugger talk transcripts stored at `docs/transcripts/rcJwvx2CTZY_ryan_fleury_raddbg_codebase_intro.json` v1@2241s and `docs/transcripts/_9_bK_WjuYY_ryan_fleury_raddbg_walkthrough.json` v2@7697s; see "Eventual Normalization Target" below). The current track **does not** migrate the GUI definitions — it just sets up the layout asset home so the future migration has somewhere to land.
## Current State Audit (as of master `1bea0d23`, branch `tier2/post_module_taxonomy_de_cruft_20260627`)
### Already Implemented (DO NOT re-implement)
- **`themes/` directory + path/loader stack (the PARALLEL pattern this track mirrors):**
- `themes/` at repo root contains 8 built-in themes (`nord_dark.toml`, `monokai.toml`, etc.). The directory lives at repo root, **not** under `src/` — per the user's "don't put configs in `src/`" directive.
- `src/paths.py:60` declares `themes: Path`; `src/paths.py:83` resolves it to `root_dir / "themes"`; `src/paths.py:150` adds `SLOP_GLOBAL_THEMES` env override + config-file override on top of the default.
- `src/theme_models.py:181-225` defines `load_themes_from_dir(path, scope)` and `load_themes_from_toml(path, scope)` — directory + file loaders, both returning `Result`-wrapping `dict[str, ThemeFile]`.
- `src/theme_2.py:340-346` calls `load_themes_from_disk()` which iterates `cfg.themes` and merges `load_themes_from_dir(...)` per scope.
- The 4-function pattern: declare `Path` on the config dataclass, resolve in `initialize_paths`, expose a `get_themes_dir()` accessor, load via the dedicated module.
- **`tests/artifacts/manualslop_layout_default.ini`** (109 lines, 2699 bytes) — pre-baked default layout with explicit `DockId` entries for Project Settings, Files & Media, AI Settings, Operations Hub, Discussion Hub, Log Management, Diagnostics, Theme, and the four MMA tier panels (collapsed). Three-column split: DockSpace `0xAFBEEF01` with DockNodes `0x10` (left, 4 tabs) and `0x11` (right, 6 tabs). Docstring lists the iter-step procedure: "open sloppy.py, arrange, quit (HelloImGui auto-saves), copy resulting INI over this one."
- **`live_gui` fixture ships the default layout** (`tests/conftest.py:700-712`): copies `tests/artifacts/manualslop_layout_default.ini` to `temp_workspace / "manualslop_layout.ini"` before spawning `sloppy.py --enable-test-hooks`. Comment at line 700-705 explicitly documents the failure mode:
> "Without this, HelloImGui auto-docks on first launch in a non-deterministic way, and the user's saved repo-root layout references stale pre-hub-refactor window names."
- **`App._diag_layout_state()`** (`src/gui_2.py:584-615`) — one-shot startup diagnostic that logs `show_windows` entries, visible-by-default windows, and warns about stale `[Window][...]` entries in the INI that reference post-refactor-renamed windows (e.g. "Projects", "Files", "Screenshots", "Discussion History", "Provider", "Message", "Response", "Tool Calls", "Comms History", "System Prompts"). Already wired into `_post_init` at line 580.
- **`commands.reset_layout`** (`src/commands.py:342-378`) — sets every `show_windows[*]` to True and deletes the layout INI. Docstring (line 351-362) acknowledges: "User will need to restart sloppy.py for the dock layout to fully take effect."
- **HelloImGui save on shutdown** (`src/gui_2.py:1494-1515` via `_shutdown_save_ini_result`, called from `App.shutdown` line 972-973): `imgui.save_ini_settings_to_disk(app.runner_params.ini_filename)` writes whatever ImGui has in its settings registry. **Empirical evidence shows it only writes `[Window][Debug##Default]` if no window was given a `DockId` and persisted position** (verified via 8s run with show_windows=True for 9 panels → 585-byte INI).
- **`ini_filename` resolution** (`src/gui_2.py:681`): `self.runner_params.ini_filename = "manualslop_layout.ini"` — relative to cwd. `ini_folder_type = IniFolderType.current_folder` on line 680. HelloImGui resolves this to `<cwd>/manualslop_layout.ini`.
- **Test workspace isolation** (`tests/conftest.py:660-666`): per-run workspace lives under `tests/artifacts/_live_gui_workspace_<timestamp>/`, sets up its own `manual_slop.toml` + `conductor/tracks/` + `config.toml`.
### Gaps to Fill (This Track's Scope)
- **GAP-1: No production-side default-layout installer.** When `manualslop_layout.ini` is missing or empty AND the user launches `sloppy.py` outside the test harness, the app does not install a sane default. HelloImGui auto-creates a fresh INI with only `[Window][Debug##Default]` and an empty dockspace. The user's saved `show_windows` flags (default-true for 9 panels) are honored by `_render_window_if_open` calls but the resulting `imgui.begin(...)` calls produce invisible floating windows. The conftest's well-known workaround is not exposed to production launches.
- **GAP-2: Hardcoded test-fixture path in production code.** `src/commands.py:371` contains `os.path.join("tests", "artifacts", "live_gui_workspace", "manualslop_layout.ini")` inside the `reset_layout` command. This path only exists inside the test runner's per-session workspace. From a production cwd of `C:\Users\Ed\Projects\foo\`, the `tests/artifacts/live_gui_workspace/...` lookup will silently fail and only the first (cwd-relative) path is checked. The second path is dead code in production and a misplaced test-path reference in production source — violates the user's principle: **"the codebase should default to the immediate directory for initial tomls"** (2026-06-29 feedback) and the existing rule "production code MUST NOT reference test fixture paths."
- **GAP-3: No `layouts/` directory + path/loader stack.** Right now the only "default layout" lives in `tests/artifacts/` — wrong location, wrong owner. The themes system has the full pattern (`themes/` + `src/paths.py` declaration + `src/theme_models.py`/`src/theme_2.py` loaders); the layouts system has nothing. This track ships the analogous `layouts/` + `src/layouts.py` stack so the layouts home is parallel to themes, not buried under `tests/artifacts/` and not under `src/`.
- **GAP-4: No regression test for the visibility-after-empty-INI scenario.** The existing `test_workspace_profiles_sim.py::test_workspace_profiles_restoration` and `test_gui_text_viewer.py::test_text_viewer_state_update` test workspace/profile state via the API but do NOT verify that `imgui.begin(...)` actually registers a docked window (i.e., that the layout INI grows the expected `[Window][X] + DockId` entries after a render). Without an INI-content regression test, GAP-1 can regress silently.
## Goals
- **G1.** When `sloppy.py` (production) launches and `cwd/manualslop_layout.ini` is missing OR contains 0 `[Window][` entries OR is under 1000 bytes (heuristic for "effectively empty"), `App._post_init` SHALL install `layouts/default.ini` (the bundled asset) to `cwd/manualslop_layout.ini` BEFORE HelloImGui loads it. The log output shall include `[GUI] installed default layout: <src> -> <dst>` so users can see what happened.
- **G2.** `App._post_init` SHALL respect the user's `show_windows` overrides from `config.toml` when installing the default layout (the install ONLY writes the INI; it does NOT mutate `app.show_windows`). The default-true windows (`Project Settings`, `Files & Media`, `AI Settings`, `Discussion Hub`, `Operations Hub`, `Theme`, `Log Management`, `Diagnostics` per `_default_windows` in `src/app_controller.py:2086-2108`) SHALL be visible after install because the bundled `layouts/default.ini` references exactly those names with `DockId` entries.
- **G3.** `commands.reset_layout` (`src/commands.py:342-378`) SHALL remove the hardcoded `tests/artifacts/...` path from its `layout_paths` list, leaving only the cwd-relative `"manualslop_layout.ini"`. The `live_gui` workspace path is owned by the test fixture, not the app.
- **G4.** A new `layouts/` directory at repo root SHALL exist parallel to `themes/`. The new asset `layouts/default.ini` SHALL be a `git mv` of `tests/artifacts/manualslop_layout_default.ini` (preserving git history). The `src/paths.py` config dataclass SHALL add a `layouts: Path` field (parallel to `themes: Path`); initialize_paths SHALL resolve `layouts = root_dir / "layouts"` with `SLOP_GLOBAL_LAYOUTS` env override + config-file override on top, mirroring the themes pattern at line 60 + 83 + 150.
- **G5.** A new `src/layouts.py` module SHALL be added (parallel to `src/theme_2.py`/`src/theme_models.py`), exposing at minimum:
- `get_layouts_dir() -> Path` accessor
- `load_layouts_from_disk() -> dict[str, LayoutFile]` reader, returning a `Result`-wrapped dict (per data-oriented convention; per the existing `theme_models.load_themes_from_dir` shape)
- The `LayoutFile` dataclass as a `@dataclass(frozen=True, slots=True)` per the project's C11/Odin/Jai-in-Python value-type mandate (no `dict[str, Any]`)
- **No new `.py` file beyond this `src/layouts.py`; the loader reuses the existing `Result[T]` plumbing in `src/result_types.py` and follows the `theme_models.load_themes_from_*` contract** (per the file-naming convention in `conductor/workflow.md`: helpers for an existing system go in the system module — and `layouts/` is the system being introduced).
- **G6.** Add `tests/test_default_layout_install.py` that:
- Removes `cwd/manualslop_layout.ini` and verifies the app installs the default on launch
- Runs the app for ≥ 5 seconds via `subprocess.Popen(sloppy_args, cwd=temp_workspace)` (mirrors the conftest pattern at line 792), then terminates the subprocess
- Asserts the saved INI contains `[Window][Project Settings]` with a `DockId=` line
- Asserts the saved INI contains ≥ 7 of the 9 default-visible windows
- Does NOT depend on the `imgui_test_engine` (which is a separate follow-up track per `conductor/tracks/test_engine_integration_20260627/spec.md`)
- **G7.** Add `tests/test_reset_layout.py` that asserts `commands.reset_layout`'s source has no `tests/artifacts/...` string and only consults the cwd-relative `"manualslop_layout.ini"`. Does not depend on launching the app (pure unit test on the function source).
- **G8.** Update `tests/conftest.py:709` to read the bundled layout from `layouts/default.ini` (new path) instead of `tests/artifacts/manualslop_layout_default.ini` (old path). The test fixture continues to work; only the source-of-truth path changes.
## Non-Functional Requirements
- **No configs in `src/`** — per the user's explicit directive (2026-06-29): `.ini` config files live at repo root (`themes/`, `layouts/`, `config.toml`, etc.), not under `src/`. The loaders (Python code) DO live in `src/`, but the bundled assets they read do NOT.
- **No day estimates** in track artifacts (per `conductor/workflow.md` §"Tier 1 Track Initialization Rules" — HARD BAN).
- **No opaque types** in new code (per `conductor/code_styleguides/data_oriented_design.md` §8.5 — Python Type Promotion Mandate). The new `LayoutFile` dataclass uses `@dataclass(frozen=True, slots=True)` with explicit fields. The `dict[str, Any]` BANNED pattern from `conductor/code_styleguides/python.md` §17 is explicitly avoided; loaders return `dict[str, LayoutFile]` (typed instances, not opaque dicts).
- **Mirror the `themes/` pattern faithfully** — the new `src/layouts.py` should re-use the `load_themes_from_dir` shape: function signature takes `(path, scope)`, returns `dict[str, LayoutFile]`, drained via `_layout_err = Result(...)`. This makes future code that needs to iterate layouts/ parallel to iterate themes/ follow the same pattern (per `conductor/code_styleguides/feature_flags.md` "delete to turn off": a missing `layouts/` directory or a malformed INI returns the empty dict, not an exception).
- **Atomic per-task commits** with git notes (per `conductor/workflow.md` §"Task Workflow" step 9-10).
## Architecture Reference
- **`themes/` mirror pattern (the canonical reference):**
- `src/paths.py:60``themes: Path = ...` field on the config dataclass
- `src/paths.py:83``root_dir / "themes"` default in the resolve function
- `src/paths.py:150``SLOP_GLOBAL_THEMES` env override + config override
- `src/paths.py:210-216``get_themes_dir()` accessor functions
- `src/theme_models.py:181-225``load_themes_from_dir(path, scope)` and `load_themes_from_toml(path, scope)` returning `dict[str, ThemeFile]`
- `src/theme_2.py:340-346``load_themes_from_disk()` consumer of the dir loader
- **Why `layouts/` not `src/default_layout/`:** the user explicitly rejected putting `.ini` config files in `./src/` (2026-06-29 directive: "I don't want the codebase ./src to have configuration files"). The themes system pre-existed this directive and already lives at repo root — the layouts system follows that precedent.
- **HelloImGui IniFolderType / save_ini_settings_to_disk:** `src/gui_2.py:680-681`, `src/gui_2.py:1494-1515`. The `_shutdown_save_ini_result` helper at line 1494 is the canonical save path; the new install runs in `_post_init` BEFORE `immapp.run(...)` (which happens after `_post_init` at `src/gui_2.py:1486`).
- **`_diag_layout_state` (`src/gui_2.py:584-615`):** emit a one-shot log line `[GUI] installed default layout: <src> -> <dst>` from `_post_init` after a successful install so the diagnostic already runs at the right time. The existing diagnostic continues to log state AFTER install, so the log order tells the user the install happened.
- **`_render_window_if_open` (`src/gui_2.py:1115-1120`):** the `_post_init` install runs before `immapp.run(...)`, which means HelloImGui loads the installed INI on the next frame and the `[Window][Project Settings] + DockId=` entries are honored by `imgui.begin(...)`. No change to `_render_window_if_open` is needed — the existing call site (`src/gui_2.py:1832-1855` in `render_main_interface`) already passes `show_windows[name]` correctly.
- **`conductor/code_styleguides/error_handling.md`:** the install is best-effort. On `OSError` / `FileNotFoundError` (asset missing in the wheel), append to `app._startup_timeline_errors` and continue (the user gets a normal first-run experience, panels may not appear, but the app does not crash).
## Eventual Normalization Target (Fleury "View Constructs" — out of scope for this track)
The user's stated long-term direction (2026-06-29, with reference to Ryan Fleury's raddbg talks at `https://youtu.be/rcJwvx2CTZY` and `https://youtu.be/_9_bK_WjuYY`, transcripts at `docs/transcripts/rcJwvx2CTZY_ryan_fleury_raddbg_codebase_intro.json` and `docs/transcripts/_9_bK_WjuYY_ryan_fleury_raddbg_walkthrough.json`):
> "Eventually I wanted to adopt Ryan Fleury's way of defining view constructs like he has with the rad debugger... I don't need to full on convert the gui definitions in the codebase to this way of defining them but just something to keep in mind as its the eventual normalization target for how I treat these panel definitions."
**The pattern, extracted from the transcripts:**
- v1@2237s: Ryan calls `imgui.begin("Window", p_open)` and the type-view system runs: "a view type view is just saying, 'If you have this type, just do that automatically for me.'"
- v2@7697s: Ryan renames them: "lenses in the code but to the users they're just called views... the type view is just saying... if you have this type, just do that automatically for me."
- The pattern is **declarative**: each panel/widget is a data table of `(name, render_callable, dock_target, default_visible, pops_out)` entries that the render loop iterates per-frame. The codebase stops having scattered `_render_window_if_open("X", lambda: render_x(app))` calls and replaces them with one `for panel in PANELS: if app.show_windows.get(panel.name): panel.render(app)`.
**Why this track sets up that future:**
1. **`layouts/` at repo root** = the home for the declarative asset (eventually a `.py` module alongside, or a TOML/INI with panel-by-panel config).
2. **`src/layouts.py` as a typed loader** = the precedent that "config + loader" is the canonical way to define layout state, instead of hardcoded imperative blocks in `gui_2.py`.
3. **`layouts/default.ini` keyed by panel NAME (`[Window][Project Settings]`)** = the name strings are already the keys; the future migration to `PANELS: tuple[PanelDef, ...]` will keep those names but add `render_callable` and `dock_target` fields.
**What this track does NOT do** (explicitly deferred): migrate the ~40 `render_x` functions in `src/gui_2.py` into declarative `PanelDef` records. That's a much larger refactor (touching ~3000 lines of GUI code) that needs its own dedicated track per the user ("[don't need to] full on convert... just something to keep in mind"). Logged in `metadata.json:deferred_to_followup_tracks` for the next planner.
## Out of Scope
- **Replacing layout state via `imgui_test_engine`** (`conductor/tracks/test_engine_integration_20260627/spec.md`) — this is a separate follow-up track. G6's regression test uses INI content as a proxy for "imgui.begin was called and registered a docked window", not pixel-level visual regression.
- **Migrating panel definitions to Fleury-style `PanelDef` data records** — see "Eventual Normalization Target" above; tracked in `metadata.json:deferred_to_followup_tracks[].panel_defs_fleury_migration`.
- **Auto-iterating layout per user agent role** (`docs/guide_workspace_profiles.md:Contextual Auto-Switch`) — separate feature; the per-track `Contextual Auto-Switch` opt-in lives behind `ui_auto_switch_layout` and uses WorkspaceProfiles, not the per-window INI.
- **Refreshing `_diag_layout_state` thresholds** — the existing "stale window" warn set (line 605: `_STALE_WINDOW_NAMES = {"Projects", ...}`) is unchanged by this track.
- **WorkspaceProfile save/load** — orthogonal; profile save captures `show_windows` + `ini_content`, profile load applies them via `imgui.load_ini_settings_from_memory` (`src/gui_2.py:927`). The install on first run does not interact with profiles.
- **Layout editing UI** (`src/gui_2.py:render_operations_hub` "Workspace Layouts" tab) — unchanged.
- **Adding more than one bundled layout to `layouts/`** — `default.ini` is enough for this track; users can hand-author `my-layout.ini` and switch via WorkspaceProfile. Future track may add `compact.ini`, `wide.ini`, etc.
## See Also
- `docs/guide_workspace_profiles.md` — Workspace profiles (orthogonal but conceptually adjacent)
- `conductor/tracks/test_engine_integration_20260627/spec.md` — ImGui Test Engine integration (deferred follow-up for visual regression coverage)
- `conductor/code_styleguides/feature_flags.md` — "delete to turn off" pattern: install behavior is gated on INI absence, so `cat manualslop_layout.ini` to leave a no-op stub (≥ 1000 bytes / ≥ 1 `[Window][` entry) suppresses the install
- `conductor/code_styleguides/error_handling.md` — boundary handling for the install path
- `conductor/tech-stack.md` §"`src/paths.py`" — the existing themes pattern is the canonical reference for the new layouts path resolution
- Video transcripts (Fleury talks): `docs/transcripts/rcJwvx2CTZY_ryan_fleury_raddbg_codebase_intro.json`, `docs/transcripts/_9_bK_WjuYY_ryan_fleury_raddbg_walkthrough.json` — recorded by `scripts/video_analysis/extract_transcript.py`
@@ -0,0 +1,75 @@
# Track state for default_layout_install_20260629
# Updated by Tier 2 Tech Lead as tasks complete
[meta]
track_id = "default_layout_install_20260629"
name = "Default Layout Install + Hardcoded Path Cleanup + layouts/ Stack"
status = "active"
current_phase = 0
last_updated = "2026-06-29"
[blocked_by]
# None. This track is independent.
[blocks]
# None. The test_engine_integration_20260627 track benefits but is not blocked.
[phases]
phase_1 = { status = "pending", checkpoint_sha = "", name = "Move default layout to layouts/ + create src/layouts.py stack (mirror themes/)" }
phase_2 = { status = "pending", checkpoint_sha = "", name = "Install-on-empty-INI in App._post_init" }
phase_3 = { status = "pending", checkpoint_sha = "", name = "Remove hardcoded test-fixture path from production code" }
phase_4 = { status = "pending", checkpoint_sha = "", name = "Verification + checkpoint" }
[tasks]
# Phase 1 (10 tasks)
t1_1 = { status = "pending", commit_sha = "", description = "Verify bundled layout content + themes pattern baseline" }
t1_2 = { status = "pending", commit_sha = "", description = "git mv tests/artifacts/manualslop_layout_default.ini -> layouts/default.ini" }
t1_3 = { status = "pending", commit_sha = "", description = "Update tests/conftest.py:709 to layouts/default.ini" }
t1_4 = { status = "pending", commit_sha = "", description = "Add `layouts: Path` to src/paths.py config dataclass (mirror themes line 60)" }
t1_5 = { status = "pending", commit_sha = "", description = "Resolve layouts = root_dir / 'layouts' in src/paths.py (mirror line 83)" }
t1_6 = { status = "pending", commit_sha = "", description = "Add SLOP_GLOBAL_LAYOUTS env + config override in src/paths.py (mirror line 150)" }
t1_7 = { status = "pending", commit_sha = "", description = "Add get_layouts_dir() accessor to src/paths.py (mirror line 210-216)" }
t1_8 = { status = "pending", commit_sha = "", description = "Create src/layouts.py loader module (mirror src/theme_models.py + src/theme_2.py)" }
t1_9 = { status = "pending", commit_sha = "", description = "Verify src/layouts.py imports + returns empty dict cleanly" }
t1_10 = { status = "pending", commit_sha = "", description = "Commit phase 1 with git note (relocation + layouts/ stack + future Fleury target)" }
# Phase 2 (9 tasks)
t2_1 = { status = "pending", commit_sha = "", description = "Write 3 failing tests in tests/test_default_layout_install.py" }
t2_2 = { status = "pending", commit_sha = "", description = "Confirm RED (tests fail for install-logic-missing reason)" }
t2_3 = { status = "pending", commit_sha = "", description = "Implement _install_default_layout_if_empty helper in src/gui_2.py" }
t2_4 = { status = "pending", commit_sha = "", description = "Wire helper into App._post_init BEFORE _diag_layout_state" }
t2_5 = { status = "pending", commit_sha = "", description = "Add drain helper _install_default_layout_if_empty_result per data-oriented convention" }
t2_6 = { status = "pending", commit_sha = "", description = "Confirm GREEN (all 3 tests pass)" }
t2_7 = { status = "pending", commit_sha = "", description = "Run adjacent tests/test_gui*.py batch; no regression" }
t2_8 = { status = "pending", commit_sha = "", description = "Commit phase 2 with git note" }
t2_9 = { status = "pending", commit_sha = "", description = "User Manual Verification: standalone launch with deleted INI; panels visible" }
# Phase 3 (7 tasks)
t3_1 = { status = "pending", commit_sha = "", description = "Write tests/test_reset_layout.py failing test for path cleanup" }
t3_2 = { status = "pending", commit_sha = "", description = "Confirm RED (test reads source via inspect and asserts dead path is gone)" }
t3_3 = { status = "pending", commit_sha = "", description = "Remove hardcoded tests/artifacts/... line from src/commands.py:reset_layout" }
t3_4 = { status = "pending", commit_sha = "", description = "Update commands.reset_layout docstring (line 351-362)" }
t3_5 = { status = "pending", commit_sha = "", description = "Confirm GREEN" }
t3_6 = { status = "pending", commit_sha = "", description = "Run tests/test_commands*.py batch; no regression" }
t3_7 = { status = "pending", commit_sha = "", description = "Commit phase 3 with git note" }
# Phase 4 (6 tasks)
t4_1 = { status = "pending", commit_sha = "", description = "Run batched verification per workflow.md §Phase Completion Verification" }
t4_2 = { status = "pending", commit_sha = "", description = "Empirical reproduction of original bug (production cwd, manual)" }
t4_3 = { status = "pending", commit_sha = "", description = "Phase 4 checkpoint commit + verification git note" }
t4_4 = { status = "pending", commit_sha = "", description = "Append phase checkpoint SHAs to plan.md" }
t4_5 = { status = "pending", commit_sha = "", description = "Commit final plan update" }
t4_6 = { status = "pending", commit_sha = "", description = "Add row to conductor/tracks.md + commit in same batch" }
[verification]
phase_4_g1_install_on_empty_ini = false
phase_4_g2_overrides_cleared = false
phase_4_g3_path_cleanup = false
phase_4_g4_regression_tests = false
phase_4_g5_layouts_at_root = false
phase_4_g6_paths_layouts_field = false
phase_4_g7_src_layouts_py = false
phase_4_g8_conftest_path_update = false
phase_4_no_test_paths_in_src = false
phase_4_no_configs_in_src = false
phase_4_user_signoff = false
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long