Web: remote hosts load only after the first terminal settles; a refused open spins forever #373

Open
opened 2026-11-05 22:34:12 +00:00 by kayg · 3 comments
Owner

Found during #305 end-to-end runs (J241 comment 80333, J257 comment 80552).

What happens: in a fresh browser session whose Console has no window yet, the web app never loads the remote host list. The command palette and Console show "No hosts yet" or only the server's own machine. Remote hosts appear only after a first terminal window has opened and settled. In J241's run the first "Open shell on …" opened the server's own console, because the remote host wasn't listed yet, and that open was refused with no_login.

Where: apps/tracer/src/canvas/product.ts:125 and :312. The host list starts only after the first terminal settles.

Also seen: when that local console open is refused ({"error":"terminal unavailable","reason":"no_login"}), the window spins forever instead of showing the refusal (frames in compute01:~claude/j241/logs/e2e-terminal9.out).

Expected: remote hosts load with the page, whether or not a terminal is open, so "Open a terminal" and the palette always offer them. A refused open shows its reason.

Workarounds in the test drivers: open a window with "+" first (J257), or open any Console window first (J241).

Found during #305 end-to-end runs (J241 comment 80333, J257 comment 80552). **What happens:** in a fresh browser session whose Console has no window yet, the web app never loads the remote host list. The command palette and Console show "No hosts yet" or only the server's own machine. Remote hosts appear only after a first terminal window has opened and settled. In J241's run the first "Open shell on …" opened the **server's own** console, because the remote host wasn't listed yet, and that open was refused with `no_login`. **Where:** `apps/tracer/src/canvas/product.ts:125` and `:312`. The host list starts only after the first terminal settles. **Also seen:** when that local console open is refused (`{"error":"terminal unavailable","reason":"no_login"}`), the window spins forever instead of showing the refusal (frames in `compute01:~claude/j241/logs/e2e-terminal9.out`). **Expected:** remote hosts load with the page, whether or not a terminal is open, so "Open a terminal" and the palette always offer them. A refused open shows its reason. Workarounds in the test drivers: open a window with "+" first (J257), or open any Console window first (J241).
Author
Owner

J312 finish — branch fix-console-hosts-373, head 4335dde473235b6c2b151afec1a33b7f6e8180de (base origin/dev 37c93637e).

Cause. Two parts: (1) the empty Console's text was hard-coded "No hosts yet" in views/world.ts paintEmpty, whatever hosts existed; (2) with no window at mount the remote host list waited for a first terminal to settle (product.ts), falling back only after 2 s + idle.

Fix. paintEmpty now reads sessions.hosts() (embedded + admitted, pending ones left out) and re-reads on sessions.onChange, so add/remove/pending stay current: one "open a shell" pill per host, "Add host" below; "No hosts yet" only when the list is truly empty. With no window at mount the host list starts at the next idle moment (with a window the first terminal keeps its place, D188). The palette reads the same list, so it gets them too.

Test first. apps/tracer/test/console-hosts-373.spec.ts: admitted host served over the real remote.host.list socket path, last Console window closed by key, asserts Console lists both hosts with no "No hosts yet", the palette offers "Open shell on …", and a removal updates the list. 1440×900, 393×852, 375×667 × ink, paper: 6 passed on compute01 (log /tmp/j312.log there). The first red run (before the fix) failed on the spec's own window-closing step, so I did not capture a clean red on the pre-fix code; the old code could not pass it (the text was hard-coded). Not yet run against a real server (test.ssh.kayg.org needs a deploy request): pending, see below.

Budget (compute01 build, transfer-budget). deferred gzip 58348 → 58570 of 61440 B (+222 B; brotli 51730 → 52037 of 55296), critical gzip 320911 → 320915 (noise). First paint: critical path unchanged and the only mount-time addition is one idle callback.

Screenshots (6, all read; taken before the hint was shortened, so the 375 captures still show the wrapped hint): attached; the 375 wide hint wrapped to an orphan word, so I shortened it to "Pick a host to open its shell."

Gate. scripts/verify quick PASS (all rows incl. doc comments, ui literals, tracer typecheck). verify fast not run: the compute01 queue was 11–17 deep; pending your go.

**J312 finish** — branch `fix-console-hosts-373`, head `4335dde473235b6c2b151afec1a33b7f6e8180de` (base origin/dev 37c93637e). **Cause.** Two parts: (1) the empty Console's text was hard-coded "No hosts yet" in `views/world.ts` `paintEmpty`, whatever hosts existed; (2) with no window at mount the remote host list waited for a first terminal to settle (`product.ts`), falling back only after 2 s + idle. **Fix.** `paintEmpty` now reads `sessions.hosts()` (embedded + admitted, pending ones left out) and re-reads on `sessions.onChange`, so add/remove/pending stay current: one "open a shell" pill per host, "Add host" below; "No hosts yet" only when the list is truly empty. With no window at mount the host list starts at the next idle moment (with a window the first terminal keeps its place, D188). The palette reads the same list, so it gets them too. **Test first.** `apps/tracer/test/console-hosts-373.spec.ts`: admitted host served over the real `remote.host.list` socket path, last Console window closed by key, asserts Console lists both hosts with no "No hosts yet", the palette offers "Open shell on …", and a removal updates the list. 1440×900, 393×852, 375×667 × ink, paper: 6 passed on compute01 (log /tmp/j312.log there). The first red run (before the fix) failed on the spec's own window-closing step, so I did not capture a clean red on the pre-fix code; the old code could not pass it (the text was hard-coded). Not yet run against a real server (test.ssh.kayg.org needs a deploy request): pending, see below. **Budget (compute01 build, transfer-budget).** deferred gzip 58348 → 58570 of 61440 B (+222 B; brotli 51730 → 52037 of 55296), critical gzip 320911 → 320915 (noise). First paint: critical path unchanged and the only mount-time addition is one idle callback. **Screenshots** (6, all read; taken before the hint was shortened, so the 375 captures still show the wrapped hint): attached; the 375 wide hint wrapped to an orphan word, so I shortened it to "Pick a host to open its shell." **Gate.** `scripts/verify quick` PASS (all rows incl. doc comments, ui literals, tracer typecheck). `verify fast` not run: the compute01 queue was 11–17 deep; pending your go.
Author
Owner

J312 round 2 — progress, paused by the compute01 restart notice (branch fix-console-hosts-373, head 2e95da92c, origin/dev fba745051 merged).

  1. 44 px touch target (7a498ee5a): on pointer: coarse the empty-Console pills (hosts and "Add host") are 2.75rem tall by height, not hit-slop: they are stacked 4 px apart, so slop boxes would overlap and steal taps. Desktop stays ~30 px. The spec now runs phones as touch devices and asserts every pill ≥ 44 px (and < 44 on desktop).
  2. Clean red on origin/dev fba745051 src + this spec (red.log attached): 6/6 fail at the host-pill assertion (Expected: 2, Received: 0), after the empty Console is visible. Green on 5e1806144: 6 passed (green.log attached).
  3. Screenshots, regenerated and all six read: the hint is one line at 375, the pills are 44 px on both phones in ink and paper, 30 px on desktop; attached.
  4. Real-server spec apps/tracer/real/console-hosts-373.spec.ts (server's own host listed in Console and palette, its pill opens the shell), one worker, using the release binary from J305's build (06c53cb40; web root is the production tracer build). First run failed on my spec's own setup (layout observer not installed before sign-in); fixed in 2e95da92c.
  5. verify quick PASS on 5e1806144 (all rows, incl. tracer typecheck).

Not done: the real-server run and a verify quick on 2e95da92c. Both were queued (position 19) on compute01 and get cut by the restart. I'll resubmit once, in the foreground, after "compute01 back, 5 slots" is posted on #402, and will note then that this run was cut by the restart.

**J312 round 2 — progress, paused by the compute01 restart notice** (branch `fix-console-hosts-373`, head `2e95da92c`, origin/dev `fba745051` merged). 1. **44 px touch target** (`7a498ee5a`): on `pointer: coarse` the empty-Console pills (hosts and "Add host") are 2.75rem tall by height, not hit-slop: they are stacked 4 px apart, so slop boxes would overlap and steal taps. Desktop stays ~30 px. The spec now runs phones as touch devices and asserts every pill ≥ 44 px (and < 44 on desktop). 2. **Clean red** on origin/dev `fba745051` src + this spec (`red.log` attached): 6/6 fail at the host-pill assertion (`Expected: 2, Received: 0`), after the empty Console is visible. Green on `5e1806144`: 6 passed (`green.log` attached). 3. **Screenshots**, regenerated and all six read: the hint is one line at 375, the pills are 44 px on both phones in ink and paper, 30 px on desktop; attached. 4. **Real-server spec** `apps/tracer/real/console-hosts-373.spec.ts` (server's own host listed in Console and palette, its pill opens the shell), one worker, using the release binary from J305's build (06c53cb40; web root is the production tracer build). First run failed on my spec's own setup (layout observer not installed before sign-in); fixed in `2e95da92c`. 5. `verify quick` PASS on `5e1806144` (all rows, incl. tracer typecheck). **Not done:** the real-server run and a `verify quick` on `2e95da92c`. Both were queued (position 19) on compute01 and get cut by the restart. I'll resubmit once, in the foreground, after "compute01 back, 5 slots" is posted on #402, and will note then that this run was cut by the restart.
Author
Owner

J312 round 2 finish — branch fix-console-hosts-373, head e541f229fdf1e9e8f68b6cd36d3405238d5a981f (origin/dev fba745051 merged). The earlier run on this head's parent was cut by the compute01 restart (and my first real-server runs failed for the reason below); this is the resubmitted run.

Real-server spec: PASS (real3.log): real/console-hosts-373.spec.ts, one worker, web build of this head, release server binary built from a dev descendant (fba745051 is an ancestor of it; worktree j288). It signs in, closes the only window, and the empty Console lists the server's own host (screenshot real-empty-console.png, read), the palette offers "Open shell on ", and the pill opens the shell. 1 passed.

verify quick: PASS on e541f229f (quick3.log, all ten rows, including tracer typecheck and doc comments).

Finding, not mine: the shared real-spec sign-in fails on dev. enrol() ends by waiting for the "Not saved — keep this tab open" notice to clear, and on a fresh sign-up there are two identical notices, so Playwright throws a strict-mode violation. It happens on unmodified origin/dev with an existing spec (real/layout-session-incarnation.spec.ts: basedev.log, BASE_EXIT=1), and with J305's older binary. Likely a duplicate toast from the #377/#395 notice work. I did not fix it (another area). My spec calls enrol(page, server, { settle: false }), a new optional flag that skips only that wait. Worth its own issue.

Earlier on this issue: clean red on pre-fix source (red.log), green mock spec 6/6 (green.log), six screenshots with 44 px touch pills. verify fast was not run (queue 15–22 deep all night; running it before merge is the orchestrator's gate).

**J312 round 2 finish** — branch `fix-console-hosts-373`, head `e541f229fdf1e9e8f68b6cd36d3405238d5a981f` (origin/dev `fba745051` merged). The earlier run on this head's parent was cut by the compute01 restart (and my first real-server runs failed for the reason below); this is the resubmitted run. **Real-server spec: PASS** (`real3.log`): `real/console-hosts-373.spec.ts`, one worker, web build of this head, release server binary built from a dev descendant (`fba745051` is an ancestor of it; worktree j288). It signs in, closes the only window, and the empty Console lists the server's own host (screenshot `real-empty-console.png`, read), the palette offers "Open shell on <host>", and the pill opens the shell. `1 passed`. **`verify quick`: PASS** on `e541f229f` (`quick3.log`, all ten rows, including tracer typecheck and doc comments). **Finding, not mine: the shared real-spec sign-in fails on dev.** `enrol()` ends by waiting for the "Not saved — keep this tab open" notice to clear, and on a fresh sign-up there are two identical notices, so Playwright throws a strict-mode violation. It happens on unmodified origin/dev with an existing spec (`real/layout-session-incarnation.spec.ts`: `basedev.log`, `BASE_EXIT=1`), and with J305's older binary. Likely a duplicate toast from the #377/#395 notice work. I did not fix it (another area). My spec calls `enrol(page, server, { settle: false })`, a new optional flag that skips only that wait. Worth its own issue. Earlier on this issue: clean red on pre-fix source (`red.log`), green mock spec 6/6 (`green.log`), six screenshots with 44 px touch pills. `verify fast` was not run (queue 15–22 deep all night; running it before merge is the orchestrator's gate).
Sign in to join this conversation.
No labels
launch-qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/infraternal#373
No description provided.