aboutsummaryrefslogtreecommitdiffstats
path: root/docs
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
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')
-rw-r--r--docs/HANDOVER.md24
-rw-r--r--docs/roadmap.md66
2 files changed, 84 insertions, 6 deletions
diff --git a/docs/HANDOVER.md b/docs/HANDOVER.md
index 641ac12..1e3fe96 100644
--- a/docs/HANDOVER.md
+++ b/docs/HANDOVER.md
@@ -167,9 +167,11 @@ bar. See `docs/roadmap.md` for each with its measurements.
fails.
- **Single-line KDL needs `;` between nodes.** `tab x { pane }` will not parse;
emit multi-line.
-- **A tab template destroys tab purposes** — identity is a tab `purpose`, and
- templating replaces the tab's root layout. That is why `sl0ppi` inlines the
- template into each tab instead of emitting `default_tab_template`.
+- **A tab template used to destroy tab purposes** — `parse_tab_node_with_template`
+ never read `purpose` off the tab node, so the template's (none) won. Fixed;
+ `sl0ppi` emits `default_tab_template` again, which is also what gives a tab
+ created at runtime a status bar. If you ever revert that line, the CLI has to
+ go back to inlining, and runtime tabs lose their bar.
- **The tab test harness does no rendering**, so `panes_to_hide` is always empty
and stack-related bugs cannot be reproduced in it. Use a scripted pty.
- **`action list-panes` hides borderless plugin panes once a client attaches.**
@@ -189,9 +191,19 @@ bar. See `docs/roadmap.md` for each with its measurements.
- **The pane's geometry is not where its frame is drawn.** With a gap, the frame
is inset from the allocation: use `Pane::frame_rect()` for anything the user
can see, `position_and_size()` only for the layout solver.
-- **Clean up test sessions.** A background-created session I left behind is what
- produced a "MY FOCUS" bug report from the user. The live checks now reap their
- own servers; anything else you spawn by hand, kill by pid via `comm`.
+- **Never kill a `sl0ppij` you cannot PROVE is yours.** I killed the user's live
+ client on the reasoning "there are no user sessions on this box" -- a guess,
+ not evidence, and wrong. The evidence was right there and said the opposite: a
+ check's processes always carry that run's own socket dir
+ (`--server /tmp/sl0p-<run>/...`) or `attach sl0ptest-...`, while a bare
+ `sl0ppij` with a cwd in the repo is a human's. If the args do not contain your
+ own temp dir, it is not yours.
+- **Clean up test sessions, and DELETE them.** A background-created session I
+ left behind is what produced a "MY FOCUS" bug report from the user, and
+ `kill-session` alone leaves them listed as "EXITED - attach to resurrect":
+ 35 of mine had silently filled the session picker before I noticed. The live
+ checks now `delete-session` their own session by name; anything you spawn by
+ hand, clean up the same way.
- **`send_cli_scroll_up_action` flakes** (scrolled 1 line where the snapshot has
2), seen once in ~10 full runs. It is the CLI-action raciness already tracked
above, not a rendering bug -- re-run before chasing it.
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