The short answer
In AgentSight v1.0.31, a slow Node no longer has to delay useful results from fast peers. The fleet refresh starts one asynchronous probe per Node with Promise.all, but each probe callssetFleetSamples as soon as its own overview succeeds or fails. The outer promise is therefore an end-of-refresh barrier for bookkeeping, not the point at which rows first become visible.
This is progressive rendering, not a claim that the network became faster. A particular Node can still take time to exhaust its Direct and relay paths, and the fleet-level loading state remains active until all probes settle. The useful difference is that already-resolved Nodes are no longer hidden behind the slowest one.
Why this is a distributed-systems problem in a frontend
A fleet page is aggregating independent machines with different failure modes: a laptop may be reachable by a browser-local Direct connection, a remote server may only have Controller relay, and another Node may be offline. Treating those requests as one atomic page load couples their tail latencies. If nine Nodes answer in 200 ms and the tenth times out, an all-or-nothing UI can turn a partial-success system into an apparent outage.
AgentSight already keeps detailed runtime data authoritative on each Node. The v1.0.31 frontend follows the same independence at presentation time: each machine owns its current sample, reachability result, transport, and update time instead of waiting for a single fleet response to become complete.
The refresh path has two different barriers
| Stage | What waits | What the user can see | Failure meaning |
|---|---|---|---|
| Refresh starts | Nothing per Node yet. | Existing rows are retained where possible; new rows enter a checking/unreachable placeholder state. | The fleet is not declared failed just because work is still in flight. |
| One Node settles | Only that Node's Direct/relay attempts. | Its sample is replaced immediately with online overview data or an unreachable result. | Slow peers remain independent. |
| All Node probes settle | The outer Promise.all. | The fleet leaves its global loading phase. | Only if every sample is unreachable does the UI set the fleet-wide “no overview reachable” error. |
Step 1: seed per-Node state before the network finishes
refreshFleet first snapshots the active organization and marks the refresh in flight. It then rebuilds the visible sample list from the known cloud Nodes. If a Node already has a sample, that sample is kept; otherwise the row starts as checking when there is a Direct connection or cloud session that could reach it, and unreachable when no transport exists.
Keeping existing samples matters during refresh. The UI does not need to blank an already useful fleet while a new read is happening. The transient state belongs to the machine being checked, not to the entire page.
Step 2: fan out one independent probe per Node
The implementation maps the current Node directory to asynchronous probes. Each probe starts with an unreachable sample and then tries the transports available for that machine. A browser-saved Direct connection is attempted first. A Controller relay client can be attempted when the cloud session exists and the relay check reports the Node online.
Relay status is also stored per Node. A failed relay probe does not erase a successful Direct result from a different machine, and a session-expiration error is handled separately from ordinary reachability failure. The transport decision is therefore local to the Node rather than a fleet-wide boolean.
Step 3: publish each result before the slowest peer finishes
The important line is inside the per-Node asynchronous function, before the outerPromise.all returns. Once a Node has a usable overview, its sample is marked online with the selected transport and an update timestamp. Whether the probe succeeds or exhausts its options, the code then replaces only the matching item in fleetSamples.
This makes completion order visible. A fast machine can move from checking to online while a slow peer is still probing. The final array returned by Promise.all is used to decide whether every Node failed; it is not used as a batch payload that must be complete before the first row can render.
Generation guards keep old refreshes from winning races
Progressive updates create a second problem: an older request can finish after the user switches organizations or starts a newer activation. AgentSight uses generation counters for directory, fleet, and active-Node work. A fleet refresh captures its generation and checks that value before updating relay status, replacing a sample, reporting an error, or clearing the loading state.
The code also records which organization currently owns the in-flight fleet refresh. Together, these guards make a late response harmless instead of allowing stale data from the previous organization to overwrite the current view. This is cancellation by result invalidation rather than assuming every underlying request can be physically cancelled at the same instant.
Session detail is kept out of the fleet critical path
v1.0.31 also narrows what must be loaded when a reader opens a session. The session workspace defines conversation, process, and analysis as separate tabs. ProcessTreeView andSessionAnalysis are dynamically imported, and event-display processing is performed only for the analysis tab. The initial session detail request is guarded against duplicate concurrent loads, while quiet refreshes can follow live-message changes.
This does not mean the browser never downloads those components, nor does it establish a device-level latency benchmark. It means the source-level dependency graph no longer requires every process/analysis view to be in the initial path for every session. Product PR #209 separately reports successful production builds and browser tests at narrow viewports, but its asset-size comparison is explicitly not a physical-device load-time result.
The request timeout is still part of the tail
Progressive rendering does not eliminate per-machine timeout behavior. The v1.0.31 browser client uses a 12-second default request timeout and a 30-second session-request timeout. A slow Direct or relay operation can therefore remain in flight while faster peers have already become useful. That is exactly the case progressive presentation is designed to tolerate.
The same client also avoids automatically replaying ambiguous HTTPS writes. After a failed HTTPS fetch, onlyGET and HEAD reads are eligible for the local-address-space fallback; a write is rethrown because the remote side may already have accepted it. That rule is orthogonal to fleet loading, but it illustrates the same design principle: retries that are safe for reads are not automatically safe for effects.
What v1.0.31 does—and does not—guarantee
| Claim | v1.0.31 behavior |
|---|---|
| One slow Node blocks every visible result. | No. Completed per-Node samples are written into the fleet as they settle. |
| The full refresh completes before the slowest probe settles. | No. The global loading phase still waits for the outer probe set to settle. |
| A late result from an old organization can overwrite the new view. | Generation checks suppress stale state updates. |
| Process and analysis views must be loaded for every fleet row. | No. They are session-detail views and are dynamically loaded when that workspace needs them. |
| The release changes authorization or Controller policy. | No. Product PR #209 explicitly scopes those policies out of the change. |
| The release proves lower end-user latency on arbitrary hardware. | No. The source and tests establish the loading behavior; they do not provide a general device-latency benchmark. |
How to inspect the behavior yourself
The reproducible artifact for this article is the released source, not a synthetic timing number. Start at refreshFleet in the v1.0.31 web page. Follow the per-Node map, the transport loop, the in-probe setFleetSamples, and then the final all-unreachable check after Promise.all. Next inspect the session workspace for dynamic process/analysis imports and tab-scoped event processing.
Product PR #209 is useful as the validation record: it documents narrow-screen browser coverage, a slow-Node test, pending-send unmount behavior, and the single-attempt failed-HTTPS-write case. The release tag fixes the exact product snapshot so future frontend changes do not silently change the claims on this page.
Where this fits in the AgentSight architecture
The broader AgentSight architecture page explains why detailed runtime data remains Node-authoritative and how Direct and Controller paths fit together. The Direct Node credential article owns the pairing and capability model. This page owns a narrower question: once the browser has several machines it can try to reach, how does the fleet UI avoid making the slowest machine the visibility barrier for every other one?
Primary sources
- AgentSight v1.0.31 release
- Product PR #209: progressive fleet loading, on-demand session views, mobile behavior, and validation
- v1.0.31 fleet refresh and Node activation implementation
- v1.0.31 session workspace: lazy process/analysis components and detail refresh behavior
- v1.0.31 Node client: request timeouts, Direct/relay transports, and write retry boundary