The portal identifies a signed-in user through its user directory, UserIdentityCache. The directory is an in-process index of every User node by email. A live nodeType:User query fills it. UserContextMiddleware, ResolveHttpCaller and CircuitAccessHandler read it on every request. Before its first snapshot arrives, the directory answers "the mesh user index has not received its first snapshot yet". That answer means Unavailable, not "no such user" (see #974).

What went wrong

The directory is a DI singleton. A singleton is built when something first resolves it, and only the request paths resolved it. So the first signed-in request on a pod built the directory and asked it in the same call. The query subscribes on the query pool, so the answer is always Unavailable at that moment. Every new pod therefore served one degraded identity, and logged:

UserContextMiddleware: mesh user index UNAVAILABLE for … (the mesh user index has not received its first snapshot yet) — falling back to the email local-part for the partition key.

Measured on the control instance on 2026-10-16 (#6850): 23 such lines in 24 hours across 8 pod generations, one per pod, each at that pod's first signed-in request, and none after it. The line appeared on every image in that window, so it was not a regression of one build. The "We could not check your account" page users reported that morning came from a different instance and a different cause: per-node hub activation failing on a module-container fault (#6847).

What it does now

UserDirectoryReadiness (src/MeshWeaver.Hosting.AspNetCore/Portal) is both a hosted service and a health check. The portal's service defaults register it (AddDefaultHealthChecks).

The guard

UserDirectoryOpensAtStartTest (test/Memex.Portal.Shared.Test) runs a real mesh. Its directory provider holds the snapshot until the test releases it:

With the open removed from ApplicationStarted, the first test fails: "ApplicationStarted must open the user directory read before any request asks it". Without the probe's retry, the open-failure test fails on "could not be opened". Without the rejection, the incomplete snapshot hydrates the directory, no failure is recorded, and the incomplete-snapshot test times out waiting for one.

The Bake Gate Only Stalls a Roll · Query Fan-In Stall Terminal