Skip to content

Activity tracking times out: _UserActivity per-node hub never delivers initial state to the mirror #5115

Closed as not planned

Description

@systemorph

What is failing

The MeshWeaver.Graph.ActivityTracking service fails to record user-activity updates: it creates/updates a _UserActivity node, then the awaiting update times out after 30s because no initial state ever arrives at the mirror — the per-node hub either never activated, or activated but its MeshDataSource produced no snapshot.

Probable cause

Confidence: medium. The exception explicitly names a wedged per-node hub (already tracked as MeshWeaver#2896) and RLS silently rejecting the prior CreateNode as the leading candidates, and states it cannot distinguish between routing failure, a wedged owner, or a lost reply. This fingerprint — BaseStateTimeoutException with "no change item at all reached the mirror" — matches the same symptom reported across many users and paths over the past month, so this is very likely the same underlying defect rather than a new one: a _UserActivity hub (or its MeshDataSource initial read) failing to hydrate under load. The concrete case is user rbuergi, path ClientA/Esl/GitHubActionsIdentityAndBuildQueueMail, on the memex namespace.

Impact

Low for this instance — one occurrence on one pod, an activity-history entry silently not recorded. However, the folded parent fingerprint recorded 425 occurrences across 59 pods over ~6 weeks for the same log site, so the systemic issue is ongoing and user-facing activity tracking is intermittently unreliable; if you can connect the two, the aggregate impact is material.

Where to look

  • MeshWeaver.Graph.ActivityTracking — the code path that creates/updates user/_UserActivity/<path> nodes and awaits the hub's initial state (30s bound via MeshNodeStreamHandle.BaseStateTimeoutException).
  • Investigate why a subscribed hub acks but produces no frame: cold MeshDataSource, per-node hub still activating, or RLS rejecting the CreateNode under the service identity.
  • Known related issues: MeshWeaver#1174 (prior ticket for this exact log site, filed 2026-09-18, likely a duplicate — close as such after confirming) and MeshWeaver#2896 (wedged per-node hub).

Evidence

Fingerprint 38ea9b265feaa23e
Category MeshWeaver.Graph.ActivityTracking
Severity Error
Exception System.TimeoutException
Namespace memex
Pods memex-portal-deployment-75b545bbd-gwrc6
Occurrences 1
First seen 2026-09-21 08:42:23Z
Last seen 2026-09-21 08:42:23Z
Routing not determined — no configured route matches the category MeshWeaver.Graph.ActivityTracking. This repository is the configured fallback, not a finding about who owns the fault; the category names the LOGGER, which may not be the subject.
Recent log lines
2026-09-21 08:42:23Z memex-portal-deployment-75b545bbd-gwrc6 fail: MeshWeaver.Graph.ActivityTracking[0]
      Failed to track activity for user=rbuergi path=ClientA/Esl/GitHubActionsIdentityAndBuildQueueMail
      System.TimeoutException: Update aborted: no initial state arrived for 'rbuergi/_UserActivity/ClientA_Esl_GitHubActionsIdentityAndBuildQueueMail' within 30s. Likely causes — (1) RLS silently rejected the prior CreateNode, (2) the path is misspelled / points at a namespace no NodeType claims, (3) the node was deleted between create and update, or (4) the per-node hub activated but its MeshDataSource didn't load the node from persistence. NO change item at all reached the mirror inside the bound — no snapshot ever hydrated. This does NOT establish that the owner never answered: a fresh subscribe is ACKNOWLEDGED BEFORE hydration, so an owner that acked and then produced no frame (a cold data source, a per-node hub still activating, an initial read that yielded nothing) reads identically here. Both the owner's activation/routing AND its initial read are still in scope.
       ---> MeshWeaver.Mesh.MeshNodeStreamHandle+BaseStateTimeoutException: NO change item at all reached the mirror inside the bound — no snapshot ever hydrated. This does NOT establish that the owner never answered: a fresh subscribe is ACKNOWLEDGED BEFORE hydration, so an owner that acked and then produced no frame (a cold data source, a per-node hub still activating, an initial read that yielded nothing) reads identically here. Both the owner's activation/routing AND its initial read are still in scope.
         --- End of inner exception stack trace ---

Re-addressed by the current identity function: this incident inherited 7473a637daf1e169 (Systemorph/MeshWeaver.Plugins#1796). Those nodes are superseded and will not fold, file or comment again.

Opened automatically from Admin/_LogIncident/38ea9b265feaa23e. Recurrences are folded into this issue rather than opening new ones.

Activity

  1. added
    area:meshCore subsystem: the mesh - nodes, partitions, addressing, activation
    sev:MMedium - secondary path broken, or easy workaround
    on Sep 21, 2026
  2. rbuergi commented on Sep 22, 2026

    @rbuergi
    Contributor

    Same log site as #1174 — proved by fingerprint lineage — and the 2026-09-21 decision to keep them apart is right

    Grouped as part of the area:mesh timeout cluster.

    This ticket's body says "MeshWeaver#1174 (prior ticket for this exact log site, filed 2026-09-18, likely a duplicate — close as such after confirming)". Confirmed that they are the same site, and confirming is not a reason to close.

    The evidence that it is the same site

    This ticket's footer: "Re-addressed by the current identity function: this incident inherited 7473a637daf1e169". 7473a637daf1e169 is #1174's fingerprint (its Evidence table). So the identity function re-keyed one log site from 7473a637daf1e169 to 38ea9b265feaa23e and filed a second ticket for it. Same MeshWeaver.Graph.ActivityTracking[0] category, same Failed to track activity for user=… path=…, same TimeoutException → BaseStateTimeoutException terminal. That is a split, not two faults.

    Why the split stays split

    The 2026-09-21T19:52Z consolidation comment on this ticket already decided it and gave the reason: "folding an undiagnosed family into a diagnosed root buries whichever is wrong." That is the correct rule and it holds here:

    If the family were closed on #1174's fix and the stall were a different cause, the remaining occurrences would have no ticket. If #1174 were closed into the family, its diagnosis and its #4928 gate would be lost. Keep both, cross-referenced by terminal. The general form is committed as Doc/Architecture/OneLogSiteManyTerminals (PR #5170).

    One eliminated hypothesis, recorded on #1174

    The Workspace.EvictForPath mechanism proposed on #1174 (every hot write re-hydrates a brand-new mirror inside the 30 s bound) predicted census branch one and was to be falsified once a replica carrying 48a3bee rolled. Branch one has since been read on images carrying #4428, the change that stops EvictForPath evicting the writer's own mirror — including this ticket's own 2026-09-21T08:42:23Z sample, which prints "NO change item at all reached the mirror inside the bound — no snapshot ever hydrated". So that competing hypothesis is out, and the family's cause is still open. Full reasoning and its caveat on #1174.

    Disposition

    Leave open as the symptom family, sev:M. The two discriminators the consolidation comment names are still the right next steps and I ran neither:

    1. whether the timeouts track routing saturation (RoutingGrain dispatch slots saturate with legs head-of-line blocked behind one shared-cache destination while the second pod starves on load #5009/RoutingGrain dispatch pool saturates repeatedly on portal silos; slots held through unbounded ThreadPool wait and episode-stamp splitting floods incidents #5018) — if so the cause is upstream of ActivityTracking entirely;
    2. the upsert trail's UPSERT_READ absent vs UPSERT_READ existing stage, which is durable truth and which the query cannot answer at all.

    What I did NOT establish

  3. rbuergi commented on Sep 23, 2026

    @rbuergi
    Contributor

    Duplicate of #5256. Same log site (MeshWeaver.Graph.ActivityTracking), same _UserActivity write, same terminal: "NO change item at all reached the mirror inside the bound — no snapshot ever hydrated" (branch one of the base-state census).

    The only difference is the wrapper, and the code explains it:

    #5256 carries the current-code analysis: every sample falls in a roll window, and there is a named mechanism (the owner acks a fresh subscribe, then tears down before its first frame, and the teardown announcement is suppressed). It also has the post-roll discriminators. The consolidation note here kept this ticket apart from #1174 (a diagnosed root). #1174 is now closed as fixed, so the symptom family belongs on one ticket. Closing as duplicate.

  4. rbuergi commented on Oct 11, 2026

    @rbuergi
    Contributor

    (re-posted 2026-10-11; originally by @rbuergi on 2026-09-21)

    Consolidation 2026-09-21 — 2 tickets folded here

    Folded as duplicates: #5109 #5124. Three users (rsalzmann/SecureDevelopmentFramework, rbuergi/ClientA/Esl/…, mkleiner/LearningRoadmap), one shape: ActivityTracking writes a _UserActivity node, the subscribe is acked, no initial state ever reaches the mirror, and the update aborts with MeshNodeStreamHandle+BaseStateTimeoutException at 30 s.

    Kept as a symptom family on purpose. #5109 named #1174 as its likely root and the exception text names #2896; both are hypotheses. #1174 (a CreateNodeRequest addressed to the sending hub itself is never answered) and #1122 (per-node hub DataContext init times out at 120 s) stay open — folding an undiagnosed family into a diagnosed root buries whichever is wrong.

    The two discriminators worth running

    1. Three users in one window (ActivityTracking: user-activity update times out because per-node hub never hydrates initial state #5124) points away from per-user causes — RLS rejection of the prior CreateNode, a namespace no NodeType claims, a node deleted between create and update — and toward a systemic hydration stall.
    2. Co-occurrence (ActivityTracking: user-activity update times out because per-node hub never hydrates initial state #5124): many concurrent RoutingGrain back-pressure and Orleans queue read-timeout incidents in the same window. If these timeouts track routing saturation (RoutingGrain dispatch slots saturate with legs head-of-line blocked behind one shared-cache destination while the second pod starves on load #5009/RoutingGrain dispatch pool saturates repeatedly on portal silos; slots held through unbounded ThreadPool wait and episode-stamp splitting floods incidents #5018), the cause is upstream of ActivityTracking entirely and this ticket is a symptom of that.

    Aggregate denominator, from #5115's own folded parent fingerprint: 425 occurrences across 59 pods over ~6 weeks for this log site — so the family is continuous, not a one-day event. Per-instance impact is one unrecorded activity entry (a stale "recently viewed"); no data loss beyond that, no outage — hence sev:M and not sev:H, since nothing measured shows a broken user-facing feature.

    Also on the record from #5109: the newer exception text states explicitly that a subscribe is acked before hydration, so an acked subscribe is not evidence of a live mirror.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:meshCore subsystem: the mesh - nodes, partitions, addressing, activationbugSomething isn't workingfeature:activity-trackingFeature: activity trackingsev:MMedium - secondary path broken, or easy workaround

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions