Skip to content

Telemetry runtime context keeps a stale installationId after the gateway token changes #343

Description

@MicroMilo

Summary

resolveTelemetryRuntimeContext caches the runtime context by a key that does not include the gateway token path, token mtime, or token content. However, installationId is derived from the gateway token file contents. In the same process, if the token file changes after the first call, subsequent calls with the same pilotHome / env return the cached installationId for the old token.

This is a confirmed runtime behavior. Whether it is a user-facing bug depends on the intended product semantics: if the gateway token can be rotated or regenerated during a process lifetime, the telemetry identity can become stale. If the token is intentionally immutable for the process lifetime, that invariant should probably be documented and covered by a test.

Code path

Cache / identity anchors:

  • src/telemetry/context.ts:17 defines runtimeContextCache.
  • src/telemetry/context.ts:23-26 builds the cache key and returns cached context before recomputing identity.
  • src/telemetry/context.ts:30 stores installationId from resolveInstallationId(...) in the cached context.
  • src/telemetry/context.ts:45-49 derives installationId from the gateway token file contents when the token exists.
  • src/telemetry/context.ts:162-172 builds the cache key from pilotHome, commit/version env values, process.execPath, and process.argv[1], but not from the token path or token contents.

Steps to reproduce

Validation level: dynamically reproduced in one Node process using the real resolveTelemetryRuntimeContext, resolveGatewayTokenPath, and hashTelemetryId functions with a temporary pilotHome.

  1. Create a temporary pilotHome.
  2. Write server-token with token-A.
  3. Call resolveTelemetryRuntimeContext({ pilotHome, env }).
  4. Replace server-token with token-B.
  5. Call resolveTelemetryRuntimeContext({ pilotHome, env }) again in the same process.

Observed result:

{
  "firstMatchesTokenA": true,
  "secondStillMatchesTokenA": true,
  "secondMatchesTokenB": false,
  "staleCacheObserved": true
}

Expected behavior

If runtime token changes are supported, the second call should either recompute installationId from token-B or invalidate the cached runtime context when the token changes.

If runtime token changes are not supported, the code should make that invariant explicit with a test or documentation so callers do not expect token rotation to update telemetry identity in-process.

Actual behavior

The second call returns the cached context created from token-A, even after the token file contains token-B.

Existing coverage

I checked current open and closed issues/PRs for runtimeContextCache token installationId, resolveTelemetryRuntimeContext token, buildRuntimeContextCacheKey installationId, and adjacent gateway/token/telemetry titles. Existing token/gateway issues appear to cover different root causes, such as WebSocket reconnect behavior or token exposure, not this telemetry cache key behavior.

Suggested fix

If token rotation should be reflected in telemetry identity, include token identity in the cache invalidation boundary, such as token path plus mtime or a token hash, or clear runtimeContextCache from the token rotation path.

If token rotation is intentionally out of scope for a running process, add a test that documents the invariant and consider a short comment near buildRuntimeContextCacheKey.

Suggested tests

  • Add a same-process test with token A -> B and assert the intended installationId behavior.
  • If recomputation is intended, assert that the second call matches hashTelemetryId("token-B").
  • If cache stability is intended, assert that runtime token changes are ignored by design and document why.

Submitted with Codex.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions