Per-Process Infrastructure Hubs

The rule: a hub that exists once per PROCESS — hosted under the mesh root, not backed by a node — is addressed portal/{role}-{meshRootId}. The mesh id makes the address unique to the process. The portal type is stream-routed, so the router carries a delivery from any silo to the process that hosts the hub. In production that carrier is the directed pod-hub transport: production declares no client-hosted address types, and a multi-silo host registers no memory stream (#6603). The memory-stream fallback exists only where an address type is declared client-hosted, such as the test rig. If the hosting process has gone, the router refuses the delivery loudly.

Hub Address Role
Node-operation execution portal/nodeops-{meshId} runs node CRUD off the router (MeshExtensions.NodeOperationExecutionHub)
Read issuing portal/reads-{meshId} issues bounded node reads (MeshExtensions.ReadIssuingHub)
Activity tracking portal/tracking-{meshId} originates user-activity writes (ActivityTrackingHub.GetActivityTrackingHub)

Why the address carries both halves (#6605)

The activity-tracking hub used to live at activity/_tracking, and that address got both halves wrong:

The tracking hub is per process ON PURPOSE. Activity writes must originate from a stable, registered hub whose cache is the process's shared cache/{meshRootId}, never a transient per-connection hub (see ActivityTrackingHub). So the fix keeps one hub per process and only gives it the address its siblings already had.

Where it is pinned

ActivityTrackingHubCrossSiloTest (MeshWeaver.Hosting.Orleans.Test) runs on two silos:

On the old address, the first two fail and the third passes.