5ad062b13a
Bug: when cwd/manualslop_layout.ini is missing/empty after first-run,
post-deletion, or post-corrupt-INI, the GUI panels are not visible
despite show_windows[name] = True. Root cause is structural: imgui.begin
without [Window][name] + DockId in the INI produces a floating window
that gets clipped by the full-screen dockspace. Empirically confirmed:
8s of running produces a 585-byte INI containing only [Window][Debug##Default].
Fix shape (4 phases):
Phase 1: relocate tests/artifacts/manualslop_layout_default.ini ->
layouts/default.ini (at repo root, parallel to themes/ per
user directive 'no configs in src/'); add src/paths.py
'layouts' field + SLOP_GLOBAL_LAYOUTS env override (mirror
themes pattern at line 60/83/150/210-216); add src/layouts.py
loader module (mirror src/theme_models.py + src/theme_2.py
contract; LayoutFile = @dataclass(frozen=True, slots=True)
per the C11/Odin/Jai-in-Python value-type mandate).
Phase 2: install-on-empty-INI in App._post_init. _install_default_layout_if_empty
helper + drain helper, called BEFORE _diag_layout_state and
BEFORE immapp.run. logs '[GUI] installed default layout: <src> -> <dst>'.
Phase 3: drop hardcoded 'tests/artifacts/live_gui_workspace/...' path
from src/commands.py:reset_layout line 369-376 (dead code in
production; violates 'production code defaults to immediate
directory' directive 2026-06-29).
Phase 4: 3-test regression suite in tests/test_default_layout_install.py
+ 1 unit test in tests/test_reset_layout.py; user manual verify
(delete INI, run sloppy.py standalone, see panels).
TDD red-first per task. Atomic per-task commits with git notes (per
conductor/workflow.md §Task Workflow step 9-10). No day estimates per
conductor/workflow.md §Tier 1 Track Initialization Rules.
Out of scope (deferred): panel_defs_fleury_migration - migrate the ~40
render_x functions to declarative PanelDef records per Ryan Fleury's
raddbg 'type view' / 'lens' pattern. Spec §Eventual Normalization Target
documents the design sketch + the transcripts at docs/transcripts/.
This track sets up layouts/ at repo root + src/layouts.py as the typed
loader so the future migration has somewhere to land.
Tracks.md row will be added in Phase 4 (Task 4.6) when the track ships.
111 lines
9.8 KiB
JSON
111 lines
9.8 KiB
JSON
{
|
|
"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."
|
|
}
|
|
]
|
|
}
|