Nodes visited: 11. Comparison count: unchanged.
In a set of local tests in September 2026, our discovery prototype kept reporting the same counts. That was true with 32 agents in the network and remained true with 512. Requests traveled at most two nearby hops. The counts looked exactly as intended.
Elapsed time told a different story. The 95th percentile of query latency rose from 5.66 milliseconds to 47.64 milliseconds. A sixteenfold increase in network size made the query more than eight times slower.
The conflicting numbers pointed to work happening outside the visit counter.
The system toured the network before the request left
First, what does this query do? Each agent in the prototype stores a signal usable for discovery and connects to a few neighbors. When a request reaches a node, it must decide whether nearby objects are worth exploring. The system constructs a neighborhood summary for this purpose, combining public signals from the node and its one-hop neighbors.
Think of a city map. The query intends to walk a few streets; a neighborhood summary is a signpost at an intersection, helping it choose where to go next.
The early implementation took a convenient approach: remake the signposts for every node before sending the request on its way.
# Simplified structure of the early request path
adverts = build_all_neighborhood_summaries(network)
return walk_local_routes(request, adverts)
The second line really does follow a local route. The first has already scanned the entire network.
The existing resource counters mostly covered propagation and comparison, so they accurately reported “11 nodes visited.” That metric measured work during propagation. Rebuilding all summaries happened beforehand, took time, and grew with the network—but was missing from that account.
Data systems offer a familiar parallel. A database can return few rows after scanning many. A query with LIMIT can still pay substantial startup costs for sorting or index construction. PostgreSQL’s EXPLAIN documentation explicitly distinguishes output rows, startup cost, and total cost. To interpret those quantities, we must know which work each covers.
For this agent prototype, the diagnosis was specific enough to act on: work saved by local access was being done again before local access even began.
Build a summary at the moment it is needed
We replaced batch construction with per-node construction. A summary is built only when the query reaches an edge and needs its neighborhood. If the same synchronous query needs it again, the computed result is reused.
# Simplified revised request path
adverts = {}
def summary_for(edge_id):
if edge_id not in adverts:
adverts[edge_id] = build_one_neighborhood_summary(edge_id)
return adverts[edge_id]
return walk_local_routes(request, summary_for)
Here, adverts lives for one query only. The next query reads current nodes and connections afresh, naturally incorporating updates, joins, and departures. That simplicity is deliberate. The prototype runs synchronously, with no concurrent network mutation during a discovery operation. Reuse within a query captures the main benefit without introducing cross-request cache invalidation.
Building all summaries remains useful for diagnostics or a full-network snapshot. We removed it from the mandatory path of an ordinary query.
We also added two counters tied directly to the work: summaries constructed and summary contributors read. The visit count remains. The new counters make preparation observable too.
The same workload, with a flatter latency curve
The comparison used the same machine, topology, queries, and configuration. Each size ran 12 discovery requests on a fixed bidirectional ring, with every node connected to neighbors at offsets 1 and 3. Requests traveled at most two hops. These are historical records from that short local test on a constructed topology.
| Agents in the network | p95 before | p95 after |
|---|---|---|
| 32 | 5.66 ms | 4.28 ms |
| 128 | 13.21 ms | 4.91 ms |
| 512 | 47.64 ms | 5.15 ms |
Figure 1. Historical before-and-after comparison on the same workload. The horizontal axis lists three tested sizes; connecting lines guide the eye. Each point is the p95 of 12 queries.
At 512 agents, throughput rose from approximately 22 to 209 queries per second. Each query still visited 11 agents. It now constructed just 10 summaries and inspected 50 contributors, with the same two counts at all three sizes.
The paired analysis checked candidate counts, handoff counts, visit counts, and existing resource counters. Those recorded quantities stayed unchanged. The interpretation is therefore specific: the change removed preprocessing the query did not use. The new latency curve and the added work counters support the same explanation.
This result applies to the single-machine, synchronous, constructed topology used then. Each group has only 12 requests, with p95 computed by linear interpolation on that short sample. Production tail latency also depends on concurrency, networking, and changing data. The useful result here is finding and removing a real piece of request preparation that grew with the entire pool.
A local algorithm needs a local request path
An algorithm can be economical in its core loop while scanning everything during initialization, serialization, index maintenance, or cleanup. Our omission was summary construction. The new counters put it inside the cost of the same request.
A small experiment can expose similar work in another system: hold fixed the objects a request actually needs, add more irrelevant objects, and measure end-to-end time. If core operation counts stay fixed while time keeps rising, follow the request path in search of work that has not yet been counted.
After the repair, the request builds each summary it actually needs: 10 summaries, 50 contributors. A local query no longer prepares signposts for the whole network.
Materials: the September 1, 2026 Discovery Front local capacity test and paired analysis. This publication round checked the original comparison files, run configuration, and current summary-construction code. Code in the article is simplified for explanation. Exact locations are in the publication package’s SOURCE-NOTES.md. This engineering note revisits an existing experiment.