aboutsummaryrefslogtreecommitdiffstats
path: root/docs/roadmap.md
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-13 22:07:45 +0200
committeruser <user@clank>2026-08-13 22:07:45 +0200
commita8ea4e888938e562885b1a0f009f5743939a879b (patch)
tree2ae5df21d4919cfe128830376b55dca814418496 /docs/roadmap.md
parentchecks: ignore __pycache__ (the up check imports a sibling check) (diff)
downloadsl0ppi-a8ea4e888938e562885b1a0f009f5743939a879b.tar.gz
sl0ppi-a8ea4e888938e562885b1a0f009f5743939a879b.tar.xz
sl0ppi-a8ea4e888938e562885b1a0f009f5743939a879b.zip
sl0p: keep a templated tab's purpose, so runtime tabs get a status bar
Clicking the bar's `+` made a tab with no status bar. The button only exposed it: pressing `n` in TAB mode did the same, in any `sl0ppi up` session. The chain: a generated layout had no default_tab_template, so a tab created at runtime had nothing to take a bar from. It had none because parse_tab_node_with_template read a tab node's name, cwd and focus but never its `purpose` -- so templating erased the purpose that IS identity here (`sl0ppi ls` finds project tabs by it), and the CLI worked around that by inlining the template into every tab instead of emitting it. Fixed at the root: a templated tab keeps its own purpose, and the CLI emits `default_tab_template` again. The generated layout also shrinks -- one copy of the bar's configuration instead of one per tab. The two properties trade off against each other, so sl0ppi-up-live.py now asserts both at once: `sl0ppi ls` still sees a tab per project, and every tab including one created at runtime has exactly one status bar. Confirmed by reverting each half separately: without the parser fix the tabs lose their purpose and `ls` shows "alpha —"; without the CLI change the runtime tab has zero bars, which is the reported bug. Two measurement traps cost an hour here and are now written down: counting bars by grepping dump-layout also counts the template and every swap layout ("4 bars for 3 tabs"), and list-panes stops reporting borderless plugin panes for a tab once a client has rendered it. Also in here, from the same session: - the split button check found buttons by searching for " + " on any row with a frame glyph, which matches the stack list's "+N more" once two panes sit side by side, and then reports the product broken. It now requires the frame corner the button is drawn against. - the checks killed their sessions but did not delete them, so each run left an "EXITED - attach to resurrect" entry: 35 had quietly filled the session picker. They now delete-session by name. - and the trap that cost the user their running client: I killed a bare `sl0ppij` because "there are no user sessions on this box". That was a guess, not evidence, and wrong. A check's processes always carry that run's own socket dir or `attach sl0ptest-...`; a bare `sl0ppij` with a cwd in the repo is a human's. Written into the handover next to the `pkill -f` trap, which is the same mistake in a different costume.
Diffstat (limited to 'docs/roadmap.md')
-rw-r--r--docs/roadmap.md66
1 files changed, 66 insertions, 0 deletions
diff --git a/docs/roadmap.md b/docs/roadmap.md
index 068129f..675f82d 100644
--- a/docs/roadmap.md
+++ b/docs/roadmap.md
@@ -355,6 +355,42 @@ render half a box. That one function also returns where the content line starts,
and click routing reads it — which is why a click on the new box's border hits
nothing instead of the widget underneath.
+### A tab made at runtime had no status bar
+
+Reported as "creating a new tab with the icon from the status bar created a tab
+without statusbar" -- but the button was innocent: the `n` keybinding did it
+too. A generated session had no `default_tab_template`, so there was nothing for
+a runtime tab to take a bar from.
+
+The reason it had none was the trap recorded below: templating a tab dropped its
+`purpose`, and purpose is identity, so the CLI inlined the template into every
+tab instead. That trap turned out to be one missing line in the fork --
+`parse_tab_node_with_template` read `name`, `cwd`, `focus` and
+`split_direction` off the tab node but never `purpose`, so the template's (None)
+won. It now keeps the tab's own, and both properties hold at once:
+
+| | inlined (before) | templated (before) | templated (now) |
+|---|---|---|---|
+| tab keeps `purpose` | yes | **no** | yes |
+| runtime tab gets a bar | **no** | yes | yes |
+
+So `sessionLayoutKdl` emits `default_tab_template` again, and the generated
+layout shrank further: one copy of the bar's configuration for the session
+rather than one per tab. `singleTabLayoutKdl` still inlines -- that layout is
+handed to a session that already has a template, and emitting another would give
+the new tab two bars.
+
+`sl0ppi-up-live.py` checks both halves, because fixing either one alone
+regresses the other: every tab (including one made at runtime) has exactly one
+bar, and `sl0ppi ls` still finds a tab per project. Confirmed by reverting each
+half in turn and watching the matching assertion fail.
+
+Counting bars needs care: `dump-layout` includes the template itself and every
+swap layout, so grepping it reports definitions as if they were panes -- that
+cost an hour of chasing a doubled bar that did not exist. Count panes per tab
+from `list-panes`, and do it BEFORE any client attaches (see the trap about what
+that hides).
+
### `sl0ppi up` and the generated layout
Making the bar a `pane_template` broke `sl0ppi up` outright:
@@ -385,6 +421,36 @@ attached it stops reporting the borderless plugin pane, which had me believing
the bar was gone in cases where it was on screen the whole time. `dump-layout`
and the screen agree; `list-panes` does not.
+### A tab made at runtime now gets a status bar
+
+Clicking the bar's `+` (and pressing `n` in TAB mode) produced a tab with no
+status bar in `sl0ppi up` sessions. The button only made it visible: a generated
+layout had no `default_tab_template`, so there was nothing for a new tab to take
+a bar from.
+
+The reason it had none was `parse_tab_node_with_template`, which read a tab
+node's `name`, `cwd` and `focus` but not its `purpose` -- so templating a tab
+erased the purpose that is the CLI's notion of identity, and the CLI worked
+around it by inlining the template into every tab. That is now fixed at the
+root (`sl0p_a_templated_tab_keeps_its_own_purpose`), and the CLI emits the
+template again:
+
+| | inlined (before) | template (now) |
+|---|---|---|
+| tab keeps `purpose=` | yes | yes |
+| runtime `new-tab` has a bar | **no** | yes |
+| copies of the bar's config in the layout | one per tab | one |
+
+Both halves are checked by `sl0ppi-up-live.py`, because they trade off against
+each other: it asserts `sl0ppi ls` still sees a tab per project AND that every
+tab, including one created at runtime, has exactly one status bar.
+
+Count bars per tab from `list-panes`, not by grepping `dump-layout`: that dump
+also contains the template itself and every swap layout, so substring counting
+there reports "4 bars for 3 tabs" and sends you looking for a doubling bug that
+does not exist. And do it before any client attaches, because `list-panes` stops
+reporting borderless plugin panes for a tab a client has rendered.
+
### Still open on the bar
Content and further click targets: a close-`x` per tab, session name → session