Skip to main content
← Back to list
01Issue
BugOpenSwamp Club
AssigneesNone

Relationships

#492 reindexByUsername re-strands pre-association history and wipes sign_in_dates

Opened by keeb · 5/30/2026

Summary

The telemetry admin endpoint reindexByUsername (services/telemetry/lib/server.ts, ~lines 960-989) writes username_metrics using a path that is now inconsistent with the username_metrics projection model introduced for #491. Running a reindex on a user would silently corrupt that user's aggregate in two ways. We do not currently run reindex in production, so this is latent — filing to fix separately rather than expanding the #491 PR.

Background

#491 makes username_metrics a materialized projection of identity_map -> user_metrics: the ingest consumer and the one-time backfill both recompute a user's aggregate as the deterministic merge of ALL events on their mapped devices (including pre-association anonymous history), written with a field-scoped $set that preserves sign_in_dates. reindexByUsername is a THIRD writer of username_metrics that did not get updated.

Bug 1: re-strands pre-association history

The username_metrics write uses buildEventCounts(allEvents), where allEvents comes from Athena/S3 filtered by the frozen username column (athena_reader.ts collectEventsByUsername, WHERE username = ?). Pre-association anonymous events have no frozen username, so they are excluded. Running a reindex therefore overwrites the projection with a pre-association-EXCLUDING count, undoing the #491 fix for that user until their next authenticated ingest batch triggers a recompute.

Note: the function even computes const merged = aggregateUserMetrics(readyDocs) (the correct device-merge, which WOULD include pre-association history) just above the write, then ignores merged for the username_metrics write and uses the frozen-username allEvents instead.

Bug 2: wipes sign_in_dates

The write uses usernameMetricsCol.replaceOne({ distinct_id: username }, { ... }) with a document that has no sign_in_dates. replaceOne replaces the entire document, so it drops any existing sign_in_dates, zeroing the user's sign-in streak score. This is exactly the hazard that #491 guards against in the consumer (field-scoped $set, never replaceOne) — still live in this path.

Expected fix

Make reindexByUsername reuse recomputeUsernameMetricsProjection(db, [username]) (exported from lib/consumers/stats.ts) for the username_metrics write, so the admin reindex path produces the same projection as ingest/backfill and never touches sign_in_dates. At minimum, switch the write from replaceOne to a field-scoped $set and source counts from the device merge rather than the frozen-username event set.

Affected

  • services/telemetry/lib/server.tsreindexByUsername (~960-989)

Impact

Latent: only fires when an admin runs reindex-by-username. When it does, it silently re-strands pre-association history and zeroes sign-in streaks for the reindexed user. No CLI/user-facing trigger.

Follow-up to #491 (telemetry pre-association attribution projection).

02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED

Open

5/30/2026, 6:07:30 PM

No activity in this phase yet.

03Sludge Pulse

Sign in to post a ripple.