Skip to content

id(web): cursor presence UX remainder — tooltip modes, pin/unpin, lifecycle logging #1790

Open

Description

@dezren39

Split from rollup #1294 (TODO.md backlog), triage task 2544, judged at main HEAD e561ab5.

Already done (do not redo)

Cursor opacity fading/strobing/hover are implemented in pkgs/id/web/src/cursors.ts (fade 30s→60s minimum→5m hidden, strobe slows with fade, hover = 100% opacity + top z-index; the TODO file's own "Done?" list matches).

Remaining scope

  • Tooltip visibility modes: full / minimal / hidden toggle in the UI (minimal = cursor only, tooltip on hover ≥1s; hidden = tracked but not shown, pinned cursors exempt).
  • Click-to-enlarge tooltip with the 1s revert chain (big → tooltip → minimal), per-cursor minimize/restore lists for full and minimal modes, and pin/unpin on the big tooltip.
  • Client + server logging of cursor lifecycle (first inactive, minimum reached, removed, hover/unhover).
  • Verify inactivity is based on connection liveness (websocket pong/activity), not pointer idleness — a connected client's cursor stays visible.

Acceptance criteria

  • The modes, pin/unpin, and minimize/restore behaviours above work in the web UI with tests at the existing web/src/*.test.ts pattern level.
  • Lifecycle log lines exist client- and server-side; the liveness basis for inactivity is verified and documented in the PR.

Activity

  1. added
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    on Oct 28, 2026
  2. developing-today commented on Oct 28, 2026

    @developing-today
    Contributor
  3. added
    kind/featureNew feature or capability request
    source/queue-workerFiled or worked by the queue/worker pilot
    priority/lowNice to have; do when convenient
    effort/mMedium: expected under 1 day of work
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    on Oct 28, 2026
  4. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    Intake review

    🤖 Agent note · filed

    • Agent: fleet monitor
    • Session / ID: repo-fleet-monitor run 2026-10-28 15:19 CDT
    • Found via: monitor reconciliation
    • Task: Intake enrichment — labels normalized, live status verified
    • Expectation: effort/m; done = labels + this review + meta/enriched applied
  5. added
    queue/queuedHas a queued task in the Supabase agent queue
    task/triageQueue packet kind: verify, reproduce, and route this item
    on Nov 3, 2026
  6. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    state: triaged (coverage pass)
    Coverage pass 2026-11-03: reviewed in the fleet-wide per-issue pass (drift / overlap / already-handled / stale / blockers / ordering). Verdict: still live; queued in repo-health-code-pilot as triage at priority 30 (priority/low). If this is already handled at current main, the triage closes it with evidence; if it needs splitting, the triage files the split.
    Found via: coverage pass 2026-11-03

  7. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 3, 2026
  8. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    Triage — still live at main 9a1fe42

    Verified against fresh origin/main = 9a1fe429c8b4b6ece5fcdf1587dfdf022c63ffe6 (2026-11-03).

    Still live. None of the four remaining-scope items exist at current main:

    • pkgs/id/web/src/cursors.ts still only does opacity fade / strobe / hover restore (FADE_START_MS 30s, FADE_END_MS 60s, HIDE_MS 5m in cursor-utils.ts). No tooltip mode state, no pin/unpin, no minimize/restore lists.
    • git grep -ni "tooltipMode|minimiz|pinned|presenceLog" -- pkgs/id at main has no hits in the presence surface (only unrelated vendor/example matches).
    • Lifecycle logging: one client console.log("[cursors] Removing stale cursor:", clientID) at cursors.ts:296. Nothing for first-inactive / minimum-reached / hover / unhover, and no server-side presence lifecycle logs.
    • No open PR implements any of it (gh pr list --state open for cursor/presence returns only fix(id): canonicalize presence channels before cap (#4404) #4571 presence-channel dedup, unrelated).

    Liveness item — verified, and it currently fails the desired behaviour. Inactivity is pointer/selection idleness, not connection liveness:

    • Client lastUpdate is set only when a CURSOR message (msg 4) arrives (cursors.ts:836-847); opacity and hiding derive from that age (cursors.ts:542-548 + getOpacityForAge).
    • The client sends CURSOR only on selection/cursor change (collab.ts sendCursor). The periodic empty-text "pong refresh" only dispatches an empty transaction to re-render decorations and replies with empty text (collab.ts:643-647) — it does not refresh lastUpdate.
    • Server tracks connection liveness separately (last_activity + ping/pong, collab.rs:991-1100) and rebroadcasts existing cursors with idle_secs only to a newly joined client (collab.rs:944-965).

    => A connected client that does not move for 5 minutes has its cursor hidden from everyone. So this is a real behaviour change, not a documentation check.

    Scope / ordering for the implementing PR (fits effort/m):

    1. State model first — one presence-UI state (tooltipMode: full | minimal | hidden, pinned set, per-mode minimized set) as a pure module with tests in the existing web/src/*.test.ts pattern. Modes, pin and minimize interact, so fix the state model before UI.
    2. Tooltip modes — full / minimal (cursor only, tooltip on hover ≥1s) / hidden (tracked but not shown; pinned exempt).
    3. Tooltip interaction — click-to-enlarge plus the 1s revert chain big → tooltip → minimal; per-cursor minimize/restore for full and minimal; pin/unpin from the big tooltip.
    4. Liveness fix — refresh lastUpdate on a connection-liveness tick (server empty-text ping/pong or a presence heartbeat) so a connected idle client stays visible; keep idle_secs backdating for initial load. Document the liveness basis in the PR.
    5. Lifecycle logging last — client lines for first-inactive / minimum-reached / removed / hover / unhover, plus matching server-side tracing in the collab.rs presence paths.

    Blockers: none technical. Step 4 depends on step 1's state model; step 5 last. Sibling #1792 (settings/name propagation) touches the same presence surface but is separable — this issue does not need to wait on it. Parent rollup #1294 is closed; this issue stands alone. Labels stay kind/feature, app/id, effort/m, priority/low.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/idPackage/app: id (pkgs/ or apps/ in this repo)effort/mMedium: expected under 1 day of workkind/featureNew feature or capability requestmeta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/lowNice to have; do when convenientsource/queue-workerFiled or worked by the queue/worker pilottask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions