Repository navigation
perf(tray): apply an unchanged listing without rebuilding (event data plane M2a) - #370
Merged
Merged
Conversation
Event data plane M3 (zerus-604d.3). `hgs [@host] watch --json` is a long-lived NDJSON stream: hello, a bounded catalog snapshot of the live listing (rows exactly as ls --json --local --no-archives, keyed run:<run_id>), deltas with removal reasons, catalog.meta, and Activity subscriptions over stdin whose cursor is the events.sqlite3 seq that inspect --after takes. Heartbeats, gap/snapshot resync, a 4 MiB coalescing writer queue and 1 MiB frames bound it; EOF on stdin ends it. `hgs -h` prints the marker `Event stream ABI: watch-v1`; @host runs it over one SSH connection with keepalives, guarded so an older peer never reads it as a launch. Change detection uses no new dependency: a 250 ms pulse stats the listing's inputs and polls PRAGMA data_version on a held journal connection, with a 5 s safety listing for changes no file shows. Volatile observation fields are masked, so deltas carry real changes only. The serde frame types live in crates/watch-protocol (no Loro or Qt) for the desktop, the Tauri client and later the connector. The inspection's journal query is shared, not forked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Event data plane M4 (zerus-604d.4). EventStream runs one `hgs [@host] watch --json` per computer whose CLI prints the watch-v1 marker. The child, NDJSON framing, JSON parsing and the computer's catalog and Activity store live on the stream's own thread; the GUI thread receives the same BoxState a listing poll delivers and inspect-shaped Activity increments, so the existing apply paths stay unchanged. While a computer's stream is live, the tray skips its periodic listing polls and the Sessions window follows the selected session's Activity through it, polling only the Processes section at its own interval. Listings are applied at most every 2 s until M2 makes applying one cheap; Activity within 50 ms. A failed or silent stream restarts after 5 s, 15 s, 60 s and then every 5 minutes, and polling continues meanwhile. A computer without the marker keeps polling. ZERUS_EVENT_STREAM=0 or dataPlane/eventStream=false opts out. On arch, following a busy session: event lag p50 0.20 s, p90 0.28 s against 2.34 s and 2.70 s for today's 2.5 s inspect polling. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A loaded macOS runner produced one heartbeat in the fixed 180 ms the test slept (PR #369, CLI unit job). Both writer tests now wait for the expected frames with a 5 s deadline instead of sleeping a fixed time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
zerus-604d.6 and zerus-604d.7. The watcher re-derives only a session whose binding changed or whose journal rows arrived, through the listing's own row steps under the same lock, and lists all rows again when anything else changes and every 5 s. A 5 s probe covers what no file shows: tmux sessions that start, end, are renamed, attached or detached, exited agent processes, ended background work, sessions without a hook event yet, and DeepSeek and OpenCode hosts. A listing captured each live pane several times: once for the effort footer and once per eligible terminal chooser (usage limit, resume, Kimi cache hint, approval), 62 tmux capture-pane calls on arch for 35 panes. Inside the read-only status observation those readers now share one capture per pane; answers, resizes and key sends still capture afresh. On arch: a listing dropped from about 0.25 s to 0.21 s CPU, and the watcher from 12.9 % to 6.1 % of a core over 60 s. With a 15 s whole listing it measured 4.3 %, but a chooser without a hook would show up to 15 s late; that tradeoff waits for the owner. ls and inspect output are unchanged (105/105 stable rows and 831/831 stable inspect fields compared). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Windows fake CLI runs Python scripts; a /bin/sh fake never answered there, so the stream failed instead of reporting Unsupported (#369 Windows job). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Event data plane M2a (zerus-604d.2). Each listing now carries a digest, computed off the GUI thread with the observation fields masked (goal_observed_at, process_work.sampled_at, metrics, desktop_presence). When a listing matches the last one and the stored read state is unchanged, the tray only refreshes poll times, metrics and background observations; Sessions keeps its rows unless the clock changes their text, a peer crosses the staleness age or the selected session's inspection reads differently. Accounts and Machines keep their data but render only while shown, the tray menu rebuilds only when what it shows changed, the organization is serialized and sent to the swarm only when it changed, and read replies, attention marks and pending reads are applied in one unread pass (a test checks it matches the former three passes). On arch (35 rows, window shown): 5.5 ms -> 0.36 ms of GUI-thread time per unchanged listing and 5.6 ms -> 4.1 ms per changed one. The design spec also describes the watcher's incremental listing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ufna
force-pushed
the
work-ba0ed9fd-m2a
branch
from
October 27, 2026 15:24
1e9138f to
5a6e059
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Event data plane M2a (epic zerus-604d, task zerus-604d.2). Stacked on #369 (stream M3+M4); the M2a change is the last commit.
What changes
goal_observed_atandprocess_work.sampled_at, plusmetricsanddesktop_presence.SessionPresentation::textChangesAt, e.g. retry countdowns, waits, scheduled runs, midnight),FleetState::setReadState). A test checks it matches the former three passes on mixed fixtures.Measurements (arch, Release, offscreen, 35-row real listings, medians of 40 × 3 runs)
The remaining changed-listing cost is mostly
SessionsWindow::rebuild(about 3 ms), which is M2b's job.Verification (arch)
ZERUS_GUI_THREAD_CHECKS=fatal: 84/84 suites, 3021 test functions, 0 failed, 23 skipped (platform-only). Run independently by the subagent and the reviewer.test_hgsclient,test_fleetstate,test_traymenu,test_accountspage,test_machinespage,test_workspace,test_eventstreamandtest_sessionswindow.test_source_*26 OK;check-source.py0 privacy findings.Behaviour changes to note
🤖 Generated with Claude Code