J297: stale-screen note becomes a state icon in the machine pill #389

Open
opened 2026-11-06 10:36:11 +00:00 by kayg · 7 comments
Owner

Owner: ""screen may be out of date" should appear as a state icon in the machine pill rather than randomly placed text" (2026-11-06). TASTE row: "Window state is an icon in the machine pill".

Plan (est. 2 h):

  1. TerminalHooks.onStaleScreen(stale) replaces the floating note in terminal.ts; D309 state machine (stale-screen.ts) unchanged. Delete packages/ui/src/terminal-note.ts.
  2. LinkInfo.staleScreen -> LinkView.stale -> card.setStale().
  3. New shared packages/ui/src/stale-mark.ts: small screen glyph with tooltip "Screen may be out of date", tap peeks the tooltip on touch, accessible name. It lives in the machine pill, beside the connection indicator; its slot grows and shrinks (no layout jump).
  4. Specs: assert pill icon + tooltip, no .ui-terminal-note in the DOM; D309 timing assertions kept.
  5. Screenshots from a production build: 1440x900, 393x852, 375x667, ink + paper, icon showing and tooltip open.
Owner: "\"screen may be out of date\" should appear as a state icon in the machine pill rather than randomly placed text" (2026-11-06). TASTE row: "Window state is an icon in the machine pill". Plan (est. 2 h): 1. `TerminalHooks.onStaleScreen(stale)` replaces the floating note in `terminal.ts`; D309 state machine (`stale-screen.ts`) unchanged. Delete `packages/ui/src/terminal-note.ts`. 2. `LinkInfo.staleScreen` -> `LinkView.stale` -> `card.setStale()`. 3. New shared `packages/ui/src/stale-mark.ts`: small screen glyph with tooltip "Screen may be out of date", tap peeks the tooltip on touch, accessible name. It lives in the machine pill, beside the connection indicator; its slot grows and shrinks (no layout jump). 4. Specs: assert pill icon + tooltip, no `.ui-terminal-note` in the DOM; D309 timing assertions kept. 5. Screenshots from a production build: 1440x900, 393x852, 375x667, ink + paper, icon showing and tooltip open.
Author
Owner

Started. Branch stale-state-pill, base 24e6467217 (origin/dev).

Started. Branch `stale-state-pill`, base 24e646721761d55da693d393522dddfc56c3059a (origin/dev).
Author
Owner

Progress: d3548e5a4 pushed (hook -> LinkInfo -> card.setStale, new stale-mark.ts, terminal-note deleted). Typecheck clean, link.test 6/6. First spec run failed because the test-double page is the single-terminal screen (top capsule), not a window card; adding the same icon to that capsule too (it is that screen's machine pill) and retargeting the spec. Logs: compute01 ~/j297-run1.log.

Progress: d3548e5a4 pushed (hook -> LinkInfo -> card.setStale, new stale-mark.ts, terminal-note deleted). Typecheck clean, link.test 6/6. First spec run failed because the test-double page is the single-terminal screen (top capsule), not a window card; adding the same icon to that capsule too (it is that screen's machine pill) and retargeting the spec. Logs: compute01 ~/j297-run1.log.
Author
Owner

Finish. Branch stale-state-pill, head 719450f01 (base 24e646721).

What changed: the loose note is gone (terminal-note.ts deleted). The terminal reports the D309 state through onStaleScreen; the machine pill shows a small screen icon (new packages/ui/src/stale-mark.ts). Tooltip "Screen may be out of date"; on touch a tap on the icon peeks the same tooltip; the icon has role=img and an accessible name. It appears and goes with a 200 ms slot open/close plus opacity/scale (compositor only; no motion under reduced motion). D309 timing logic unchanged. Shown in both machine pills: the window card pill (canvas) and the single-terminal screen's capsule.

Gate: scripts/verify quick on compute01: PASS, all rows (scope guard, migration names, vendoring, fmt, doc coverage, shape lints, doc comments on diff, fixed test waits, ui literals, tracer typecheck). Log: compute01 ~/j297-verify.log. I did not run verify fast; the orchestrator's merge gate will.
Stale-screen specs, one worker, at the head: 8 passed (1.4m), log ~/j297-spec.log. link.test.ts: 6 pass. Specs assert the pill icon, its tooltip, accessible name, that the pill's vertical position, height and centre line do not move, that no .ui-terminal-note exists, and keep the D309 timing cases (no flash for a redrawing program, none at an unchanged size).

Findings:

  • The test-double page is the single-terminal screen (centred capsule), not a window card, so the spec measures that capsule by its centre line. It grows from its middle, animated.
  • On phones the host name got squeezed to "i…" with the icon showing; fixed: below 480 px the capsule drops the round-trip milliseconds while the icon shows (screenshots below are after the fix).

Not proven: the canvas window-card icon screenshots force the slot via the DOM on the mock windows page (those windows have no live terminal). The real-PTY canvas flow is covered only by the edited real specs (real/stale-screen-d309-review.spec.ts, real/stale-note-257-review.spec.ts), which I did not run (they need the real server build). Please run them or ask for it.

Screenshots (production build, 2x, looked at all of the tooltip and icon-pill ones): 1440x900, 393x852, 375x667, ink and paper, icon showing and tooltip open, for the capsule (j297-<size>-<theme>-*.png) and the window pill (j297-canvas-*). Originals on compute01 ~/j297-evidence/.

Finish. Branch `stale-state-pill`, head 719450f01 (base 24e646721). **What changed:** the loose note is gone (`terminal-note.ts` deleted). The terminal reports the D309 state through `onStaleScreen`; the machine pill shows a small screen icon (new `packages/ui/src/stale-mark.ts`). Tooltip "Screen may be out of date"; on touch a tap on the icon peeks the same tooltip; the icon has role=img and an accessible name. It appears and goes with a 200 ms slot open/close plus opacity/scale (compositor only; no motion under reduced motion). D309 timing logic unchanged. Shown in both machine pills: the window card pill (canvas) and the single-terminal screen's capsule. **Gate:** `scripts/verify quick` on compute01: PASS, all rows (scope guard, migration names, vendoring, fmt, doc coverage, shape lints, doc comments on diff, fixed test waits, ui literals, tracer typecheck). Log: compute01 `~/j297-verify.log`. I did not run `verify fast`; the orchestrator's merge gate will. Stale-screen specs, one worker, at the head: 8 passed (1.4m), log `~/j297-spec.log`. `link.test.ts`: 6 pass. Specs assert the pill icon, its tooltip, accessible name, that the pill's vertical position, height and centre line do not move, that no `.ui-terminal-note` exists, and keep the D309 timing cases (no flash for a redrawing program, none at an unchanged size). **Findings:** - The test-double page is the single-terminal screen (centred capsule), not a window card, so the spec measures that capsule by its centre line. It grows from its middle, animated. - On phones the host name got squeezed to "i…" with the icon showing; fixed: below 480 px the capsule drops the round-trip milliseconds while the icon shows (screenshots below are after the fix). **Not proven:** the canvas window-card icon screenshots force the slot via the DOM on the mock windows page (those windows have no live terminal). The real-PTY canvas flow is covered only by the edited real specs (`real/stale-screen-d309-review.spec.ts`, `real/stale-note-257-review.spec.ts`), which I did not run (they need the real server build). Please run them or ask for it. **Screenshots** (production build, 2x, looked at all of the tooltip and icon-pill ones): 1440x900, 393x852, 375x667, ink and paper, icon showing and tooltip open, for the capsule (`j297-<size>-<theme>-*.png`) and the window pill (`j297-canvas-*`). Originals on compute01 `~/j297-evidence/`.
Author
Owner

Correction: I looked at all 12 tooltip screenshots and 3 of the 4 attached icon-pill crops. 16 of the 36 files are attached; the rest (full-page icon-only shots and the remaining crops) are on compute01 ~/j297-evidence/ and I did not review them one by one.

Correction: I looked at all 12 tooltip screenshots and 3 of the 4 attached icon-pill crops. 16 of the 36 files are attached; the rest (full-page icon-only shots and the remaining crops) are on compute01 ~/j297-evidence/ and I did not review them one by one.
Author
Owner

J298 review of stale-state-pill @ 719450f01: REQUEST CHANGES

The owner rule is met: the "screen may be out of date" state is an icon in the machine pill. I found no floating note anywhere. Two visible motion and layout defects and one reuse problem remain, and the 257 real spec cannot run (that one is not this branch's fault).

I read BRIEF-COMMON.md, CLAUDE.md, TASTE (the new "Window state is an icon in the machine pill" row, chip centring, descenders, motion) and D309. I did not run verify on this branch. I built the tracer from the branch on compute01 and ran the real specs plus my own captures. Evidence is in compute01:~claude/j298-evidence/ and ~claude/j298-real*.log. Screenshots are attached to this comment.

Owner rule: met

  • No floating note anywhere: git grep finds no terminal-note code left, and the DOM has no .ui-terminal-note. After a resized reattach in the test double I scanned the document for any visible "out of date" text outside the tooltip: 0 hits at all 6 viewport and theme combinations (j298-measure.jsonl).
  • Real reattach through the D309 logic: real/stale-screen-d309-review.spec.ts passed both tests (a silent real shell shows the icon after a reattach that changed its size, and Ctrl+C clears it; an idle shell reloaded at the same size never shows it). This is my run at 12:08 IST, j298-real.log lines 28–29, screenshots stale-review-real-pty-note.png and …-reload-idle.png. The icon sits in the window's own pill. The top capsule on the canvas carries no terminal state (attached).
  • Single-terminal mode shows the icon in the capsule; the canvas capsule hides it (CSS rule), as the owner's words imply.

Findings

1. P2 (visible, repeatable): the round-trip text snaps in and collides when the icon clears, and the host name jumps width.
The phone rule .capsule:has(.ui-stale[data-shown]) .capsule-rtt { display: none } is instant, while the slot and icon animate for 160–240 ms.

  • At +70 ms after the state clears, "300 ms" is back flush against "SSH shell" with the fading icon drawn over it (393×852, 375×667 and also at 1440 where "297 ms" collides with the ghost icon). See clearing shots.
  • The host name jumps in the same instant: 393 px goes from 69.6 px ("infrat…") with the icon to 36.5 px ("in…") after; 375 px goes from 51.6 px to 18.5 px ("i…"). Measured in j298-measure.jsonl.
  • TASTE: "Every state change moves… never swap" and "Labels never collide".
  • Fix: let the dropped round-trip text leave on the same animated slot (width and opacity), or keep both. Do not use display: none.

2. P2 (reuse, one design call): a second screen glyph beside the connection indicator's "approximate" screen glyph.

  • stale-mark.ts redraws the same silhouette as ui-conn-g-approximate in connection-indicator.ts (same rect 2.4 3 11.2 8, same foot), with two inner lines changed.
  • linkView returns stale alongside the approximate state, so for about 3 s after an approximate resume the pill shows two near-identical screen icons side by side.
  • It also copies the connection indicator's tap-to-peek handler and its 160/240 ms transition values, and hard-codes 0.875rem where .ui-conn uses --ui-conn-size (1 rem). The setup ring (TASTE "Progress lives where the thing is") is the opposite design: it takes exactly its slot's size so the pill never changes width.
  • Suggest one family: share the tap-peek helper and size token, and either fold "stale" into the connection indicator as a state (one icon in the pill) or give it a clearly different glyph. The owner's list of states (TASTE "Status is an icon with motion") names "resumed with an approximate screen" as a state of that one icon.

3. P2 (the specs): real/stale-note-257-review.spec.ts cannot run, on this branch or on origin/dev.

  • It fails at enrol() with "layout observer must be installed before navigation" because it never calls watchLayout. The branch only edited note selectors in this file.
  • With a local watchLayout patch it fails differently, at settled() on the persistent "Not saved — keep this tab open" toast. The same patched spec fails identically on a clean origin/dev worktree (~claude/j298-dev257.log, DEV257_EXIT=1). So the failure is not caused by this branch, but the spec's "passes" claim has no evidence.
  • Later reruns of the d309 control spec (which passed once at 12:08) also hit the same "Not saved" toast in enrol (j298-real5.log, j298-real6.log, j298-real7.log). I did not find the cause. Treat the real-server evidence as one passing run plus unexplained harness instability. This needs its own issue, not this branch.
  • The author should say plainly which real specs pass and open an issue for the 257 spec.

4. P3: tooltip outlives its state on touch. At +520 ms after the state cleared, the phone's peeked tooltip still read "Screen may be out of date" (393x852-ink-4-cleared). set(false) should dismiss it. On desktop hover it was gone by then.

5. P3: the icon reads as neutral, not as a warning. At 14 px and 2×, the amber dotted line (--warn, dasharray 0.1 2.6) is barely visible; both lines read grey. Consider a more visible warn cue.

6. P3: the pill widens. On desktop the capsule grows about 24 px (564→588 px) when the icon opens, so the host name shifts 12 px left and the right side 12 px right (it is centred). The setup ring avoids this by taking its slot's size. This is probably fine for a one-off state, but say so.

7. P3: process. Three WIP: commits are still in the branch and 719450f01 has a title and no body. It also rewrites the easing fallback in five unrelated rules (row swipe, .ui-pill, resize grips, ui-conn-g). That is correct, since --ease-out is defined and verify.d/ui-literals.py forbids the literal, but the commit should say why. Squash or split with real messages before merge.

Checked and fine

  • Centring. Single-terminal capsule, 2×: icon centre is on the pill's and the host text's centre line within 0.01 px at 1440×900 and exactly on it at 393×852 and 375×667, ink and paper. Canvas window pill centring I could not measure (my real-server window-pill capture hit the harness failure above); J297's spec asserts it only for the capsule.
  • Host name squeeze. The icon state is better than the normal state on phones: host is 69.6 px with the icon and 36.5 px without it (the round-trip text takes the room). The capsule already squeezes the host to 2–5 characters on phones before this branch. That is a separate issue, and the RTT-drop rule is acceptable once it animates (finding 1).
  • Tooltip. Wording and material are correct in ink and paper; phone tap opens it; accessible name is set; nothing appears unprompted.
  • J297's 36 screenshots. I looked at 18 of the 36 (single-terminal and canvas, all three viewports, ink and paper, a mix of icon, pill crop and tooltip) and they match my own captures. I did not open the other 18 (the remaining combinations of the same states), so "every screenshot" is not met.

Not verified

  • Window-pill (canvas) captures of my own at 375/393 in both themes, and the clearing moment there; I only have J297's canvas shots and the real 1100×700 shot.
  • Touch tap on the real server: the tap path was only exercised in the test double (J297's spec plus my captures).
  • The approximate-snapshot status string "Reconnected. The screen may be slightly out of date." (terminal.ts:1093): I did not check whether that status element is ever visible.

Head reviewed: 719450f01952c3fb3d1dcfc5be27bbf72fcc74cc. Server binary used for the real specs: j254-current musl build (2be58ce2c), not built from this branch; the branch changes no server code.

## J298 review of `stale-state-pill` @ `719450f01`: REQUEST CHANGES The owner rule is met: the "screen may be out of date" state is an icon in the machine pill. I found no floating note anywhere. Two visible motion and layout defects and one reuse problem remain, and the 257 real spec cannot run (that one is not this branch's fault). I read `BRIEF-COMMON.md`, `CLAUDE.md`, TASTE (the new "Window state is an icon in the machine pill" row, chip centring, descenders, motion) and D309. I did not run `verify` on this branch. I built the tracer from the branch on compute01 and ran the real specs plus my own captures. Evidence is in `compute01:~claude/j298-evidence/` and `~claude/j298-real*.log`. Screenshots are attached to this comment. ### Owner rule: met - No floating note anywhere: `git grep` finds no `terminal-note` code left, and the DOM has no `.ui-terminal-note`. After a resized reattach in the test double I scanned the document for any visible "out of date" text outside the tooltip: 0 hits at all 6 viewport and theme combinations (`j298-measure.jsonl`). - Real reattach through the D309 logic: `real/stale-screen-d309-review.spec.ts` passed both tests (a silent real shell shows the icon after a reattach that changed its size, and `Ctrl+C` clears it; an idle shell reloaded at the same size never shows it). This is my run at 12:08 IST, `j298-real.log` lines 28–29, screenshots `stale-review-real-pty-note.png` and `…-reload-idle.png`. The icon sits in the window's own pill. The top capsule on the canvas carries no terminal state (attached). - Single-terminal mode shows the icon in the capsule; the canvas capsule hides it (CSS rule), as the owner's words imply. ### Findings **1. P2 (visible, repeatable): the round-trip text snaps in and collides when the icon clears, and the host name jumps width.** The phone rule `.capsule:has(.ui-stale[data-shown]) .capsule-rtt { display: none }` is instant, while the slot and icon animate for 160–240 ms. - At +70 ms after the state clears, "300 ms" is back flush against "SSH shell" with the fading icon drawn over it (393×852, 375×667 and also at 1440 where "297 ms" collides with the ghost icon). See `clearing` shots. - The host name jumps in the same instant: 393 px goes from 69.6 px ("infrat…") with the icon to 36.5 px ("in…") after; 375 px goes from 51.6 px to 18.5 px ("i…"). Measured in `j298-measure.jsonl`. - TASTE: "Every state change moves… never swap" and "Labels never collide". - Fix: let the dropped round-trip text leave on the same animated slot (width and opacity), or keep both. Do not use `display: none`. **2. P2 (reuse, one design call): a second screen glyph beside the connection indicator's "approximate" screen glyph.** - `stale-mark.ts` redraws the same silhouette as `ui-conn-g-approximate` in `connection-indicator.ts` (same rect `2.4 3 11.2 8`, same foot), with two inner lines changed. - `linkView` returns `stale` alongside the `approximate` state, so for about 3 s after an approximate resume the pill shows two near-identical screen icons side by side. - It also copies the connection indicator's tap-to-peek handler and its `160/240 ms` transition values, and hard-codes `0.875rem` where `.ui-conn` uses `--ui-conn-size` (1 rem). The setup ring (TASTE "Progress lives where the thing is") is the opposite design: it takes exactly its slot's size so the pill never changes width. - Suggest one family: share the tap-peek helper and size token, and either fold "stale" into the connection indicator as a state (one icon in the pill) or give it a clearly different glyph. The owner's list of states (TASTE "Status is an icon with motion") names "resumed with an approximate screen" as a state of that one icon. **3. P2 (the specs): `real/stale-note-257-review.spec.ts` cannot run, on this branch or on `origin/dev`.** - It fails at `enrol()` with "layout observer must be installed before navigation" because it never calls `watchLayout`. The branch only edited note selectors in this file. - With a local `watchLayout` patch it fails differently, at `settled()` on the persistent "Not saved — keep this tab open" toast. The same patched spec fails identically on a clean `origin/dev` worktree (`~claude/j298-dev257.log`, `DEV257_EXIT=1`). So the failure is not caused by this branch, but the spec's "passes" claim has no evidence. - Later reruns of the d309 control spec (which passed once at 12:08) also hit the same "Not saved" toast in `enrol` (`j298-real5.log`, `j298-real6.log`, `j298-real7.log`). I did not find the cause. Treat the real-server evidence as one passing run plus unexplained harness instability. This needs its own issue, not this branch. - The author should say plainly which real specs pass and open an issue for the 257 spec. **4. P3: tooltip outlives its state on touch.** At +520 ms after the state cleared, the phone's peeked tooltip still read "Screen may be out of date" (`393x852-ink-4-cleared`). `set(false)` should dismiss it. On desktop hover it was gone by then. **5. P3: the icon reads as neutral, not as a warning.** At 14 px and 2×, the amber dotted line (`--warn`, dasharray `0.1 2.6`) is barely visible; both lines read grey. Consider a more visible warn cue. **6. P3: the pill widens.** On desktop the capsule grows about 24 px (564→588 px) when the icon opens, so the host name shifts 12 px left and the right side 12 px right (it is centred). The setup ring avoids this by taking its slot's size. This is probably fine for a one-off state, but say so. **7. P3: process.** Three `WIP:` commits are still in the branch and `719450f01` has a title and no body. It also rewrites the easing fallback in five unrelated rules (row swipe, `.ui-pill`, resize grips, `ui-conn-g`). That is correct, since `--ease-out` is defined and `verify.d/ui-literals.py` forbids the literal, but the commit should say why. Squash or split with real messages before merge. ### Checked and fine - **Centring.** Single-terminal capsule, 2×: icon centre is on the pill's and the host text's centre line within 0.01 px at 1440×900 and exactly on it at 393×852 and 375×667, ink and paper. Canvas window pill centring I could not measure (my real-server window-pill capture hit the harness failure above); J297's spec asserts it only for the capsule. - **Host name squeeze.** The icon state is better than the normal state on phones: host is 69.6 px with the icon and 36.5 px without it (the round-trip text takes the room). The capsule already squeezes the host to 2–5 characters on phones before this branch. That is a separate issue, and the RTT-drop rule is acceptable once it animates (finding 1). - **Tooltip.** Wording and material are correct in ink and paper; phone tap opens it; accessible name is set; nothing appears unprompted. - **J297's 36 screenshots.** I looked at 18 of the 36 (single-terminal and canvas, all three viewports, ink and paper, a mix of icon, pill crop and tooltip) and they match my own captures. I did not open the other 18 (the remaining combinations of the same states), so "every screenshot" is not met. ### Not verified - Window-pill (canvas) captures of my own at 375/393 in both themes, and the clearing moment there; I only have J297's canvas shots and the real 1100×700 shot. - Touch tap on the real server: the tap path was only exercised in the test double (J297's spec plus my captures). - The approximate-snapshot status string "Reconnected. The screen may be slightly out of date." (`terminal.ts:1093`): I did not check whether that status element is ever visible. Head reviewed: `719450f01952c3fb3d1dcfc5be27bbf72fcc74cc`. Server binary used for the real specs: `j254-current` musl build (`2be58ce2c`), not built from this branch; the branch changes no server code.
Author
Owner

Round 2 finish. Branch stale-state-pill, head 3923e0bc0 (base 24e646721), history squashed from 6 commits to 3 atomic ones with full bodies.

Changes against J298's findings

  1. One mark (design call). "Stale" is now a state of the connection indicator (setStale), not a second glyph. Same box (--ui-conn-size), layers, timings, tooltip, accessible name and tap-to-peek. The glyph is the screen family with an amber badge on a ground-coloured ring (reads at 14 px). While the link is up it outranks connected/slow/resumed/approximate (one mark; they return when it clears); connecting/reconnecting/offline outrank it. stale-mark.ts and its CSS are deleted.
  2. No collision, no jump. The mark is the same box as the dot it replaces, so nothing widens or moves. Window pill width and host width are asserted equal before, during and after (spec), and the pill crops show it. The single-terminal capsule (where the RTT/host jump was) is not a production surface (mock/probe only), so it no longer carries any state and its extra CSS is gone.
  3. Touch. dismissTip takes a tap-opened tooltip down when the state clears (spec asserts it; screenshots 4-clearing show none on phone). Desktop hover correctly follows to "Connected · N ms" while the pointer is still on the mark.
  4. New finding, fixed (commit 3): on the product canvas a tap on any indicator state also opened the machine-details popover, because the pill opens on pointerup and the indicator only swallowed click. Now a touch that starts on the mark does not open details (frame.ts); the spec asserts no popover after the phone tap.
  5. History squashed; commit 1 carries rejected alternatives and why.

Gate: scripts/verify quick on compute01 at 3923e0bc0: PASS all rows incl. doc comments on diff, fixed test waits, ui literals, tracer typecheck (log compute01:~/j297-verify.log). verify fast not run (orchestrator at merge).
test/stale-screen.spec.ts, one worker, on the product canvas + test double: 8 passed (before the doc-only squash; ~/j297-real2.log). link.test.ts 6 pass.

Real spec real/stale-screen-d309-review.spec.ts (j254 server binary, not built from this branch; no server code changed):

  • Run A: both tests passed. Run B (--repeat-each=3): test 1 passed twice of three, test 2 once; the failures were the "Not saved — keep this tab open" toast in enrol (the instability you are sending elsewhere), plus one toHaveCount failure in test 2 that I did not see again in a 4x rerun (which failed only on the toast) and cannot attribute. Logs: ~/j297-real2.log, ~/j297-real3.log. real/stale-note-257-review.spec.ts was not run (cannot run on origin/dev either, per J298); I only changed its selectors.

Screenshots, product canvas window pill, 1440x900, 393x852, 375x667, ink and paper; per combination: normal pill, stale pill, stale page, tooltip open, mid-clear (+90 ms), cleared. 36 files, all attached. I viewed every one at the first capture. After the frame.ts fix I regenerated the phone ones and re-viewed their tooltip, clearing and cleared shots (12); the regenerated phone pill-crop and stale-page shots (12) I did not re-view (the same code path as the first capture). Originals: compute01:~/j297-evidence2/ (desktop, and phone before the fix) and ~/j297-evidence3/ (phone after).
What I saw: pill width unchanged between normal and stale; amber badge visible in both themes; tooltip text correct; no details popover after the phone tap; no tooltip lingering after clear on phone.

Round 2 finish. Branch `stale-state-pill`, head 3923e0bc0 (base 24e646721), history squashed from 6 commits to 3 atomic ones with full bodies. **Changes against J298's findings** 1. **One mark (design call).** "Stale" is now a state of the connection indicator (`setStale`), not a second glyph. Same box (`--ui-conn-size`), layers, timings, tooltip, accessible name and tap-to-peek. The glyph is the screen family with an amber badge on a ground-coloured ring (reads at 14 px). While the link is up it outranks connected/slow/resumed/approximate (one mark; they return when it clears); connecting/reconnecting/offline outrank it. `stale-mark.ts` and its CSS are deleted. 2. **No collision, no jump.** The mark is the same box as the dot it replaces, so nothing widens or moves. Window pill width and host width are asserted equal before, during and after (spec), and the pill crops show it. The single-terminal capsule (where the RTT/host jump was) is not a production surface (mock/probe only), so it no longer carries any state and its extra CSS is gone. 3. **Touch.** `dismissTip` takes a tap-opened tooltip down when the state clears (spec asserts it; screenshots 4-clearing show none on phone). Desktop hover correctly follows to "Connected · N ms" while the pointer is still on the mark. 4. **New finding, fixed (commit 3):** on the product canvas a tap on any indicator state also opened the machine-details popover, because the pill opens on `pointerup` and the indicator only swallowed `click`. Now a touch that starts on the mark does not open details (`frame.ts`); the spec asserts no popover after the phone tap. 5. **History** squashed; commit 1 carries rejected alternatives and why. **Gate:** `scripts/verify quick` on compute01 at 3923e0bc0: PASS all rows incl. doc comments on diff, fixed test waits, ui literals, tracer typecheck (log `compute01:~/j297-verify.log`). `verify fast` not run (orchestrator at merge). `test/stale-screen.spec.ts`, one worker, on the product canvas + test double: 8 passed (before the doc-only squash; `~/j297-real2.log`). `link.test.ts` 6 pass. **Real spec `real/stale-screen-d309-review.spec.ts`** (j254 server binary, not built from this branch; no server code changed): - Run A: both tests passed. Run B (`--repeat-each=3`): test 1 passed twice of three, test 2 once; the failures were the "Not saved — keep this tab open" toast in `enrol` (the instability you are sending elsewhere), plus one `toHaveCount` failure in test 2 that I did not see again in a 4x rerun (which failed only on the toast) and **cannot attribute**. Logs: `~/j297-real2.log`, `~/j297-real3.log`. `real/stale-note-257-review.spec.ts` was not run (cannot run on origin/dev either, per J298); I only changed its selectors. **Screenshots**, product canvas window pill, 1440x900, 393x852, 375x667, ink and paper; per combination: normal pill, stale pill, stale page, tooltip open, mid-clear (+90 ms), cleared. 36 files, all attached. I viewed every one at the first capture. After the `frame.ts` fix I regenerated the phone ones and re-viewed their tooltip, clearing and cleared shots (12); the regenerated phone pill-crop and stale-page shots (12) I did not re-view (the same code path as the first capture). Originals: `compute01:~/j297-evidence2/` (desktop, and phone before the fix) and `~/j297-evidence3/` (phone after). What I saw: pill width unchanged between normal and stale; amber badge visible in both themes; tooltip text correct; no details popover after the phone tap; no tooltip lingering after clear on phone.
Author
Owner

J310 review of stale-state-pill @ 3923e0bc0: APPROVE

The owner rule holds: "screen may be out of date" is one state of the connection indicator in the machine pill, and nothing floats anywhere. J298's findings 1, 2, 4, 5 and 6 are fixed. Finding 3 (the 257 spec) is still open. I have one doc-comment fix and a few P3 notes below. None of them blocks the merge. I ran only targeted specs, no verify. Evidence is in compute01:~claude/j310-evidence/ and ~claude/j310-real.log.

Owner rule

  • git grep finds no terminal-note or stale-mark code left. The only mention of stale-mark is one stale comment (see N1).
  • The recorder found no .ui-terminal-note in any spec run.
  • The mark takes the same box as the dot it replaces. connW is 15.39 px at 1440 and 14 px on phones, and it does not change.

J298 findings

# Result
1 collision and jump on clear Fixed. I sampled the pill and host left and width every frame for 60 frames across the clear, at 1440, 393 and 375 in ink and paper. The spread is 0.000 px for all four values in all six cases (CLEAR-SPREAD lines in j310-real.log). The round-trip text no longer jumps.
2 second screen glyph Fixed. stale is a state of .ui-conn. It uses the same tooltip, size token, layers and tap-peek, and stale-mark.ts is deleted. Precedence in effective(): stale outranks connected, resumed, approximate and slow. connecting, reconnecting and offline outrank stale, as link.ts and its test state.
4 tooltip outlives state Fixed. render() calls dismissTip when shown leaves "stale" and a tap opened the tip. The phone .tip is hidden after the clear in all six of my runs. On desktop hover the tooltip correctly turns into "Connected · N ms" while the pointer stays on the mark.
5 reads as neutral Fixed. At 2× the amber badge on its ground ring reads clearly in ink and calmly in paper. It is not louder than the connected dot.
6 pill widens Fixed. The width and left edge are identical before, during and after, at 2× (before and g in the GEOM lines).
7 history Fixed. Three atomic commits with bodies.
3 257 spec cannot run Not run. It still has no watchLayout call. The J305 fix is not on origin/dev (the spec has no watchLayout there either).

Real server

I built the server from this branch: cargo build --release -p infraternal, glibc, in compute01:~/j310-target. I built the tracer from it too, then ran real/stale-screen-d309-review.spec.ts --repeat-each=3, one worker, log ~/j310-real.log.

  • 3 passed, 3 failed. Test 1 went fail, pass, pass. Test 2 went fail, fail, pass. Every failure is the "Not saved — keep this tab open" toast in enrol (layout-devices.ts:18, strict-mode violation, 2 toasts at once). That is before any stale code runs, so it is the harness instability J305 is fixing, not this branch.
  • This branch already contains #377 ("one notice at a time"), and two toasts still appeared on the real server. J305 may want that.
  • Each of the two tests passed at least once against the real PTY with the real server, including "Ctrl+C clears the icon" and "an unchanged-size reload never shows it".
  • Not attributed: J297's one toHaveCount failure in test 2. It did not repeat in my 3 runs, since all three failures were the toast.
  • test/stale-screen.spec.ts against the product canvas: 8 of 8 passed (desktop and phone).

Screenshots

  • I viewed all 36 attached to this issue. That includes the 12 regenerated phone pill crops, 6 states × 2 themes.
  • I also made my own at dpr 2: 1440×900, 393×852 and 375×667, ink and paper. Probe /tmp/j310/j310-review.spec.ts (a scratch spec, not committed, run as test/j310-review.spec.ts). Screenshots: j310-evidence/j310-{393,375}-{ink,paper}-{details-open,mark-tap}.png.
  • Badge: amber on a ground ring, visible and calm in both themes. The tooltip, the "clearing" shots (already steady at +90 ms) and the "cleared" shots are correct and show no leftover ghost.
  • Centring at 2×. The mark's box centre is on the pill's and the host text's centre line within 0.01 px at all six combinations (connCy 92.289 vs hostCy 92.297 at 1440, and 93 vs 92.992 on phones; limit 0.5). My getBBox for the glyph, which ignores strokes, puts its drawn centre 0.61–0.67 px below and right of the box centre. The frame's 1.4 px strokes extend further than the badge ground ring on the top and left, so with strokes the offset is about 0.3 px. I also see nothing off-centre in the 2× crops. I am not raising it, but this is why the box centre is exact and the visible weight sits slightly right and low.

Touch ripple from frame.ts

Phone, 393 and 375, ink and paper (4 runs, RIPPLE lines):

  • A tap on the host name opens the details (1 popover). A tap on the machine glyph at the left of the pill opens them too (1 popover). A tap elsewhere dismisses them.
  • A tap on the mark opens only the tooltip, with 0 popovers.
  • A tap on the dot while the screen is not stale (the connected or slow dot) now also opens only the tooltip (0 popovers). Before this change it opened details as well. This follows from onMark covering every state of the indicator, not only stale. It is consistent with the owner's "tap-to-peek" rule, but it is a visible behaviour change on phones. Please mention it in the commit message or in TASTE.
  • The details no longer open on release when the finger went down on the mark. A drag from the mark still starts the move, because onMark is only read in release.

Notes (none blocks)

  • N1 (fix before merge, cheap): apps/tracer/src/stale-screen.ts:23 still says the state is presented by packages/ui/src/stale-mark.ts, which this branch deletes. D345: point it at connection-indicator.ts and setStale.
  • N2: frame.ts marks a press onMark for any non-mouse pointer, including a pen. The indicator's own touch flag only counts pointerType === "touch". A pen tap on the mark therefore does nothing at all, with no tooltip and no details. It is minor, so use one definition of "touch".
  • N3: the "0-normal-pill" shots show an amber (slow) dot, not the green connected dot. The test double's round trip is about 300 ms. It is a valid baseline for the width claim, but it is not the state a reader expects from the name. The cleared shots show the green dot correctly.
  • N4: not verified: iOS WebKit (WebKit semantics for pointer capture and click retargeting). pill.setPointerCapture and the indicator's click handler are an unusual pairing there. Chromium touch emulation is fine, so please check on a real iPhone. The Mac VM was not used (frozen).
  • N5: real/stale-note-257-review.spec.ts is still not run. Please keep the J305 follow-up open for it.

Head reviewed: 3923e0bc01bc53fb16a43bd4a42f9606e4bbb6c3.

## J310 review of `stale-state-pill` @ `3923e0bc0`: APPROVE The owner rule holds: "screen may be out of date" is one state of the connection indicator in the machine pill, and nothing floats anywhere. J298's findings 1, 2, 4, 5 and 6 are fixed. Finding 3 (the 257 spec) is still open. I have one doc-comment fix and a few P3 notes below. None of them blocks the merge. I ran only targeted specs, no `verify`. Evidence is in `compute01:~claude/j310-evidence/` and `~claude/j310-real.log`. ### Owner rule - `git grep` finds no `terminal-note` or `stale-mark` code left. The only mention of `stale-mark` is one stale comment (see N1). - The recorder found no `.ui-terminal-note` in any spec run. - The mark takes the same box as the dot it replaces. `connW` is 15.39 px at 1440 and 14 px on phones, and it does not change. ### J298 findings | # | Result | |---|---| | 1 collision and jump on clear | **Fixed.** I sampled the pill and host `left` and `width` every frame for 60 frames across the clear, at 1440, 393 and 375 in ink and paper. The spread is 0.000 px for all four values in all six cases (`CLEAR-SPREAD` lines in `j310-real.log`). The round-trip text no longer jumps. | | 2 second screen glyph | **Fixed.** `stale` is a state of `.ui-conn`. It uses the same tooltip, size token, layers and tap-peek, and `stale-mark.ts` is deleted. Precedence in `effective()`: stale outranks connected, resumed, approximate and slow. connecting, reconnecting and offline outrank stale, as `link.ts` and its test state. | | 4 tooltip outlives state | **Fixed.** `render()` calls `dismissTip` when `shown` leaves "stale" and a tap opened the tip. The phone `.tip` is hidden after the clear in all six of my runs. On desktop hover the tooltip correctly turns into "Connected · N ms" while the pointer stays on the mark. | | 5 reads as neutral | **Fixed.** At 2× the amber badge on its ground ring reads clearly in ink and calmly in paper. It is not louder than the connected dot. | | 6 pill widens | **Fixed.** The width and left edge are identical before, during and after, at 2× (`before` and `g` in the `GEOM` lines). | | 7 history | **Fixed.** Three atomic commits with bodies. | | 3 257 spec cannot run | **Not run.** It still has no `watchLayout` call. The J305 fix is not on `origin/dev` (the spec has no `watchLayout` there either). | ### Real server I built the server from this branch: `cargo build --release -p infraternal`, glibc, in `compute01:~/j310-target`. I built the tracer from it too, then ran `real/stale-screen-d309-review.spec.ts --repeat-each=3`, one worker, log `~/j310-real.log`. - **3 passed, 3 failed.** Test 1 went fail, pass, pass. Test 2 went fail, fail, pass. Every failure is the "Not saved — keep this tab open" toast in `enrol` (`layout-devices.ts:18`, strict-mode violation, 2 toasts at once). That is before any stale code runs, so it is the harness instability J305 is fixing, not this branch. - This branch already contains #377 ("one notice at a time"), and two toasts still appeared on the real server. J305 may want that. - Each of the two tests passed at least once against the real PTY with the real server, including "Ctrl+C clears the icon" and "an unchanged-size reload never shows it". - Not attributed: J297's one `toHaveCount` failure in test 2. It did not repeat in my 3 runs, since all three failures were the toast. - `test/stale-screen.spec.ts` against the product canvas: 8 of 8 passed (desktop and phone). ### Screenshots - I viewed all 36 attached to this issue. That includes the 12 regenerated phone pill crops, 6 states × 2 themes. - I also made my own at dpr 2: 1440×900, 393×852 and 375×667, ink and paper. Probe `/tmp/j310/j310-review.spec.ts` (a scratch spec, not committed, run as `test/j310-review.spec.ts`). Screenshots: `j310-evidence/j310-{393,375}-{ink,paper}-{details-open,mark-tap}.png`. - Badge: amber on a ground ring, visible and calm in both themes. The tooltip, the "clearing" shots (already steady at +90 ms) and the "cleared" shots are correct and show no leftover ghost. - **Centring at 2×.** The mark's box centre is on the pill's and the host text's centre line within 0.01 px at all six combinations (`connCy` 92.289 vs `hostCy` 92.297 at 1440, and 93 vs 92.992 on phones; limit 0.5). My `getBBox` for the glyph, which ignores strokes, puts its drawn centre 0.61–0.67 px below and right of the box centre. The frame's 1.4 px strokes extend further than the badge ground ring on the top and left, so with strokes the offset is about 0.3 px. I also see nothing off-centre in the 2× crops. I am not raising it, but this is why the box centre is exact and the visible weight sits slightly right and low. ### Touch ripple from `frame.ts` Phone, 393 and 375, ink and paper (4 runs, `RIPPLE` lines): - A tap on the host name opens the details (1 popover). A tap on the machine glyph at the left of the pill opens them too (1 popover). A tap elsewhere dismisses them. - A tap on the mark opens only the tooltip, with 0 popovers. - A tap on the dot while the screen is not stale (the connected or slow dot) now also opens only the tooltip (0 popovers). Before this change it opened details as well. This follows from `onMark` covering every state of the indicator, not only stale. It is consistent with the owner's "tap-to-peek" rule, but it is a visible behaviour change on phones. Please mention it in the commit message or in TASTE. - The details no longer open on release when the finger went down on the mark. A drag from the mark still starts the move, because `onMark` is only read in `release`. ### Notes (none blocks) - **N1 (fix before merge, cheap):** `apps/tracer/src/stale-screen.ts:23` still says the state is presented by `packages/ui/src/stale-mark.ts`, which this branch deletes. D345: point it at `connection-indicator.ts` and `setStale`. - **N2:** `frame.ts` marks a press `onMark` for any non-mouse pointer, including a pen. The indicator's own `touch` flag only counts `pointerType === "touch"`. A pen tap on the mark therefore does nothing at all, with no tooltip and no details. It is minor, so use one definition of "touch". - **N3:** the "0-normal-pill" shots show an amber (slow) dot, not the green connected dot. The test double's round trip is about 300 ms. It is a valid baseline for the width claim, but it is not the state a reader expects from the name. The cleared shots show the green dot correctly. - **N4:** not verified: iOS WebKit (WebKit semantics for pointer capture and click retargeting). `pill.setPointerCapture` and the indicator's `click` handler are an unusual pairing there. Chromium touch emulation is fine, so please check on a real iPhone. The Mac VM was not used (frozen). - **N5:** `real/stale-note-257-review.spec.ts` is still not run. Please keep the J305 follow-up open for it. Head reviewed: `3923e0bc01bc53fb16a43bd4a42f9606e4bbb6c3`.
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#389
No description provided.