aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-13 16:32:42 +0200
committeruser <user@clank>2026-08-13 16:32:42 +0200
commit694b9757423e8ed4b4bb0b57d4f8640687cc034c (patch)
tree35b95a1020faca329fc8bbdd42a35a34c1205990
parentsl0p: account for the split button in the title-alignment test (diff)
downloadsl0ppi-694b9757423e8ed4b4bb0b57d4f8640687cc034c.tar.gz
sl0ppi-694b9757423e8ed4b4bb0b57d4f8640687cc034c.tar.xz
sl0ppi-694b9757423e8ed4b4bb0b57d4f8640687cc034c.zip
docs: handover
Where the split-button work stopped, what is open, the traps that cost time, and how to verify pane/layout/mouse work on a real session rather than in the test harness.
-rw-r--r--README.md2
-rw-r--r--docs/HANDOVER.md156
2 files changed, 158 insertions, 0 deletions
diff --git a/README.md b/README.md
index 6e48f7d..96a06d4 100644
--- a/README.md
+++ b/README.md
@@ -51,5 +51,7 @@ make release # tests, then a static musl tarball
make publish # upload it to sl0ppi.sl0p.foo
```
+Picking up where the last session stopped: [docs/HANDOVER.md](docs/HANDOVER.md).
+
See [docs/roadmap.md](docs/roadmap.md), [docs/architecture.md](docs/architecture.md),
[docs/cli-design.md](docs/cli-design.md) and [FORKS.md](FORKS.md).
diff --git a/docs/HANDOVER.md b/docs/HANDOVER.md
new file mode 100644
index 0000000..467c29b
--- /dev/null
+++ b/docs/HANDOVER.md
@@ -0,0 +1,156 @@
+# Handover
+
+Written at the end of a long session. Start here.
+
+## Pick this up first: the `+` split button does not render
+
+**Feature:** a `+` at the right end of every pane's title line; clicking it
+splits that pane. Shipped in 0.1.7 (hover-gated) and 0.1.8 (always drawn).
+
+**Status: the click works, the button is invisible on a live session.**
+
+- clicking those 3 columns splits the pane — verified by injecting real SGR
+ mouse events into an attached client's pty (`1 -> 2 panes`; clicking the title
+ or mid-frame correctly does nothing)
+- the button renders in **265 unit snapshots**
+- it has never once been seen on a real session
+
+Two wrong diagnoses so far, both mine:
+
+1. "It's hover-gated and hover is broken" → removed the gate in 0.1.8, still
+ invisible. (`mouse_is_hovering_over_pane` does appear to be false live, but
+ that was not the only problem.)
+2. "The click test proves the feature" → it does not. The hit-test is purely
+ geometric and never consults the renderer, so it kept working while nothing
+ was drawn.
+
+**The strong lead, untested:** every snapshot uses zellij's DEFAULT frame
+config. The live config does not:
+
+```kdl
+pane_frames { rounded_corners true; title_alignment "center"; gap 1; padding 0 0 0 0 }
+```
+
+`render_title_right_side` is called from **three** different title builders
+(`zellij-server/src/ui/pane_boundaries_frame.rs`, lines ~889, ~915, ~983) with
+different `max_length` budgets. The snapshots only ever exercised the
+left-aligned path; `title_alignment "center"` takes another one.
+
+**Ten-second check before writing any code:** set `title_alignment "left"` in
+`~/.config/sl0ppij/config.kdl` on the test box, re-attach, look for the `+`. If
+it appears, that is the bug confirmed.
+
+**Then:** add a frame unit test using the live config's alignment/rounded/gap
+settings — the reproduction that was missing all along — and fix whichever
+builder drops the button.
+
+Code involved:
+
+| what | where |
+|---|---|
+| render + geometry | `ui/pane_boundaries_frame.rs`: `render_split_button`, `split_button_columns`, `SPLIT_BUTTON_*` |
+| click | `tab/mouse_handler.rs`: `intercept_split_button_click` |
+
+Not drawn on floating panes on purpose: the PIN control owns that corner and is
+hit-tested by its drawn position, so anything to its right moves it out from
+under the pointer (`test_ctrl_click_on_floating_pin_button_toggles_pin`).
+
+## Where the project is
+
+Everything is committed and pushed to `ssh://git@git.sl0p.foo:39327/srv/git/sl0ppi.git`.
+Released artifacts are at <https://sl0ppi.sl0p.foo> (currently 0.1.8).
+
+| phase | state |
+|---|---|
+| monorepo, 3 vendored forks with history | done |
+| rename (sl0ppij coexists with zellij) | done |
+| portable config | done |
+| tarball + installer, verified in a clean room | done |
+| `sl0ppi` CLI MVP (`up`/`ls`/`open`/`close`/`init`/`print`/`doctor`) | done |
+| site + release scripts (no CI, by choice) | done |
+
+`make` for targets, `make test` for both suites, `make release && make publish`
+to cut and upload a version, `packaging/publish.sh` verifies against the live
+URL afterwards.
+
+## Open, in the order I would do them
+
+1. **The `+` rendering** (above).
+2. **Phantom client on headless `sl0ppi up`.** `attach --create-background`
+ leaves one client in the session forever, so every pane frame shows
+ `MY FOCUS AND:`. Worked around by creating the session *by attaching* when
+ there is a tty; the headless path still leaks. Ruled out: the CLI-action
+ clients, and the creating client exiting too early (making it wait for a
+ server ack changed nothing). `screen.remove_client()` does clear
+ `connected_clients` with no early return, so instrument
+ `ScreenInstruction::RemoveClient` on a debug build to find where it is lost.
+ Cheap alternative: give the headless path its own pty (`script -qec`) and
+ kill the client afterwards — killed clients demonstrably do not leak.
+3. **bun is the AVX2 build.** Caused `Illegal instruction` on a plain KVM guest.
+ One line in `packaging/fetch-vendor.sh`: `bun-linux-x64-baseline.zip`.
+4. **`pir` needs python3 + fzf**, neither shipped. The fix is folding it into
+ `sl0ppi agent --resume` (already designed in `docs/cli-design.md`).
+5. **Tab overflow.** `sl0ppi open <name>` wants to be a fuzzy picker once a root
+ has a dozen projects.
+6. Button polish: shift/right-click for the other split direction; reuse
+ `status_bar_button_style` so it looks pressable.
+
+Fixed this session, for context: client ids were recycled (silently ate ~25% of
+`zellij action` output), suspended panes spammed resize errors, responsive
+layouts resolved against `visible_panes_count()` and never really expanded,
+runtime `new-tab` dropped pane/tab purposes, and generated sessions had no tab
+bar. See `docs/roadmap.md` for each with its measurements.
+
+## Traps worth knowing (all cost me time here)
+
+- **`pkill -f` / `pgrep -f` match your own shell's command line.** I killed my
+ own script three times, and twice killed the user's live clients. Match on
+ `comm` instead: `ps -eo pid,comm,args | awk '$2=="sl0ppij"'`.
+- **Test sessions live in the runtime dir**, not `TMPDIR`. Only
+ `SL0PPIJ_SOCKET_DIR` isolates them. A stale session called `dev` was silently
+ reused across tests.
+- **`INSTA_FORCE_UPDATE=1` churns hundreds of snapshots** (strips
+ `assertion_line`, trailing newlines). Update per-test with
+ `INSTA_UPDATE=always cargo test ... <test_name>` and verify the diff contains
+ only what you expect.
+- **git paths in loops**: `git diff --name-only` prints repo-root-relative
+ paths; running `git checkout --` on them from inside `sl0ppij/` silently
+ 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`.
+- **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.
+- **Clean up test sessions.** A background-created session I left behind is what
+ produced a "MY FOCUS" bug report from the user.
+
+## Access
+
+- test box: `ssh root@10.10.10.130` (Debian, 2 vCPU; where every live check ran)
+- prod: `ssh root@sl0p.foo`; nginx config lives in `~/dev/sl0pday/nginx/sl0p.conf`,
+ deployed with `./deploy.sh nginx/sl0p.conf` (that repo has **no** git remote)
+- `sl0ppi.sl0p.foo` currently answers **401 to everyone except 87.209.3.148**
+ (our egress). Lift by deleting the `geo` block and the `if` in the vhost.
+- new git repos: `ssh root@sl0p.foo git-new-repo <name>`
+- releases need `cargo-zigbuild` + the `ziglang` python module (both installed);
+ `protoc` 25.1 is in `~/.local/bin` for `cargo xtask proto`.
+
+## How to verify things here
+
+Unit tests are necessary and have repeatedly been insufficient — three of this
+session's bugs passed them. For anything touching panes, layouts or the mouse,
+drive a real session:
+
+```python
+# pty at a chosen size; resize or inject SGR mouse events mid-session
+pid, fd = pty.fork()
+if pid == 0: os.execvp("sl0ppi", ["sl0ppi"])
+fcntl.ioctl(fd, termios.TIOCSWINSZ, struct.pack("HHHH", rows, cols, 0, 0))
+os.write(fd, b"\x1b[<0;COL;ROWM") # left press, 1-based coords
+```
+
+then read the truth back out of `sl0ppij -s <session> action list-panes --json`
+(x, y, cols, rows per pane — two panes sharing a rect means a stack) and strip
+ANSI from the pty output before grepping for glyphs.