Skip to content

Route telemetry context through CLI, SDK, and cloud#1033

Merged
willwashburn merged 9 commits into
mainfrom
telemetry-cli-sdk-cloud
Jun 3, 2026
Merged

Route telemetry context through CLI, SDK, and cloud#1033
willwashburn merged 9 commits into
mainfrom
telemetry-cli-sdk-cloud

Conversation

@willwashburn

@willwashburn willwashburn commented Jun 3, 2026

Copy link
Copy Markdown
Member

User description

Summary

  • route Agent Relay telemetry context through CLI bootstrap and hosted cloud requests
  • send CLI telemetry through the hosted ingestion proxy at https://i.agentrelay.com by default, with POSTHOG_HOST retained as an override
  • remove client-side analytics from @agent-relay/sdk; SDK/API attribution now relies on Relaycast origin metadata
  • fold telemetry implementation into the agent-relay CLI and leave @agent-relay/telemetry as a private/deprecated workspace placeholder
  • rename the cross-service client identity contract to distinct id: AGENT_RELAY_DISTINCT_ID -> X-Agent-Relay-Distinct-Id
  • keep telemetry propagation gated on configured/enabled telemetry and preserve origin/harness/version headers

Verification

  • npm --prefix packages/cloud run build
  • npm --prefix packages/cli run build
  • npm --prefix packages/sdk run build
  • npm --prefix packages/sdk run test
  • npx vitest run packages/cloud/src/auth.test.ts
  • npx vitest run packages/cli/src/cli/bootstrap.test.ts packages/cli/src/cli/entrypoint.test.ts packages/cli/src/cli/commands/cloud.test.ts packages/cli/src/cli/telemetry/orchestrator-harness.test.ts
  • npx vitest run packages/cli/src/cli/telemetry/posthog-config.test.ts packages/cli/src/cli/telemetry/orchestrator-harness.test.ts
  • npm --prefix packages/cli run pack:validate

CodeAnt-AI Description

Route telemetry context through the CLI, SDK, cloud requests, and hosted backend

What Changed

  • CLI telemetry now records a stable distinct ID, the emitting surface, and the parent harness driving Agent Relay, and the telemetry status screen shows the distinct ID instead of the old anonymous ID.
  • Cloud requests now include Agent Relay identity and origin headers only when telemetry is enabled, so hosted services can connect CLI, SDK, and backend activity to the same source.
  • CLI telemetry now uses the hosted Agent Relay ingestion proxy by default, while still allowing a PostHog host override.
  • The SDK no longer sends its own client-side analytics, and the old public telemetry package is now a deprecated placeholder inside the monorepo.

Impact

✅ Clearer telemetry attribution
✅ Safer cloud request identity
✅ Fewer duplicate analytics events

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@willwashburn willwashburn requested a review from khaliqgant as a code owner June 3, 2026 10:03
@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR migrates telemetry implementation from a public package into the CLI, replaces anonymous identity with distinct ID tracking, adds orchestrator harness detection and propagation across the system, enriches cloud requests and broker events with telemetry context, converts SDK facade methods to async, and deprecates the public telemetry package.

Changes

Telemetry architecture refactor and context propagation

Layer / File(s) Summary
Telemetry identity model and orchestrator harness detection
packages/cli/src/cli/telemetry/config.ts, packages/cli/src/cli/telemetry/machine-id.ts, packages/cli/src/cli/telemetry/orchestrator-harness.ts, packages/cli/src/cli/telemetry/orchestrator-harness.test.ts, packages/cli/src/cli/telemetry/config.test.ts, packages/cli/src/cli/telemetry/machine-id.test.ts
TelemetryPrefs replaces anonymousId with distinctId and persists legacy prefs with normalization. createDistinctId() hashes machine ID and truncates to 16 characters. Orchestrator harness detection sanitizes explicit env vars, infers from process command names and parent walking with cycle detection and bounded depth, and returns "unknown" as fallback.
Telemetry contracts, client wiring, and PostHog config
packages/cli/src/cli/telemetry/events.ts, packages/cli/src/cli/telemetry/index.ts, packages/cli/src/cli/telemetry/client.ts, packages/cli/src/cli/telemetry/posthog-config.ts, packages/cli/src/cli/telemetry/posthog-config.test.ts
TelemetryApp and TelemetrySurface types added; CommonProperties extended with app, surface, and orchestrator_harness fields. Client initialization uses distinctId instead of anonymousId, accepts optional orchestratorHarness and builds common properties with fallback inference. PostHog default host changed to https://i.agentrelay.com.
CLI bootstrap propagation and local telemetry wiring
packages/cli/src/cli/bootstrap.ts, packages/cli/package.json, packages/cli/src/cli/commands/cloud.ts, packages/cli/src/cli/commands/setup.ts, packages/cli/src/cli/commands/cloud.test.ts, packages/cli/src/cli/lib/broker-lifecycle.ts, packages/cli/src/cli/lib/exit.ts, packages/cli/src/cli/entrypoint.test.ts
CLI imports telemetry from local ./telemetry/index.js instead of @agent-relay/telemetry. Bootstrap detects orchestrator harness, propagates version/surface/client/harness env vars and conditionally sets distinct ID when telemetry enabled. runCli captures and passes orchestratorHarness to initTelemetry. Setup messaging changed from "anonymous usage data" to "usage telemetry", status output changed from anonymousId to distinctId. Added posthog-node dependency.
Cloud telemetry headers and request integration
packages/cloud/src/telemetry-headers.ts, packages/cloud/src/auth.ts, packages/cloud/src/api-client.ts, packages/cloud/src/auth.test.ts
telemetry-headers.ts exports header constants, sanitizes environment-derived values with optional allowlist validation, disables telemetry when AGENT_RELAY_TELEMETRY_DISABLED or DO_NOT_TRACK are '1' or 'true', and provides buildAgentRelayTelemetryHeaders and appendAgentRelayTelemetryHeaders to inject telemetry into requests. auth.ts and api-client.ts append telemetry headers to all outgoing cloud requests. Tests verify header injection with distinct ID and origin vars, and header omission when telemetry disabled.
Broker telemetry harness detection and event enrichment
crates/broker/src/telemetry.rs
Broker adds harness detection (environment override, command inference with Windows suffix handling, parent process walking), stores orchestrator_harness on TelemetryClient, and injects broker-specific app and surface properties plus orchestrator_harness into PostHog payload during event tracking. Tests cover sanitization and inference logic.
SDK facade async conversions and build inclusion
packages/sdk/src/facade.ts, packages/sdk/tsconfig.build.json, packages/sdk/tsconfig.json
Facade messaging methods (send, reply, react, dm) and reconnect converted to async functions while preserving input resolution and delegation logic. facade.ts added to SDK build and typecheck include lists.
Package deprecation, build scripts, and release records
packages/telemetry/package.json, packages/telemetry/tsconfig.json, package.json, .github/workflows/package-validation.yml, CHANGELOG.md, .agentworkforce/trajectories/completed/2026-06/traj_6kef2z1redhb/*
Root typecheck and build:core scripts remove npm run build:telemetry step. @agent-relay/telemetry package marked private: true and deprecated, with build/test scripts replaced by no-op echo commands. CI workflow expanded SKIP_PACKAGES to include additional broker and telemetry targets. Changelog documents telemetry migration, SDK analytics removal, CLI default ingest host, and @agent-relay/telemetry deprecation. Trajectory files record completion of "Rope telemetry" task with context propagation decisions.

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • khaliqgant

🐰 Telemetry flows like a rope through CLI and cloud,
Distinct IDs trace the path, orchestrators proud,
Headers carry context, Relaycast receives,
SDK breathes async now, and the system believes! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 32.81% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly and concisely summarizes the main objective: routing telemetry context through multiple layers (CLI, SDK, cloud).
Description check ✅ Passed The PR description includes a comprehensive summary section that explains what changed and the impact, along with verification steps. However, it lacks a formal 'Test Plan' section from the template with checkboxes indicating which tests were added/updated or manually tested.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch telemetry-cli-sdk-cloud

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codeant-ai

codeant-ai Bot commented Jun 3, 2026

Copy link
Copy Markdown

CodeAnt AI is reviewing your PR.

@codeant-ai codeant-ai Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files label Jun 3, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements comprehensive telemetry routing across the CLI, SDK, cloud client, Rust broker, and hosted relaycast engine, introducing common properties like app, surface, and orchestrator harness. The review feedback highlights critical performance and reliability concerns: executing expensive process-tree traversals unconditionally on CLI and broker startup even when telemetry is disabled, the potential loss of telemetry events in short-lived SDK scripts due to the lack of an automatic shutdown flush, and the risk of telemetry failures disrupting the main application flow because tracking calls are not wrapped in try-catch blocks.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +118 to +119
function propagateTelemetryContextToChildren(): string {
const orchestratorHarness = detectOrchestratorHarness();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The detectOrchestratorHarness() function is called unconditionally on every CLI invocation, even when telemetry is disabled. Since this function synchronously spawns up to 8 ps processes on Unix systems to traverse the process tree, it introduces a significant performance penalty (often 50-100ms or more) to fast commands like relay --help or for users who have opted out of telemetry.

We should check if telemetry is enabled first, and only perform the expensive process traversal if necessary.

Suggested change
function propagateTelemetryContextToChildren(): string {
const orchestratorHarness = detectOrchestratorHarness();
function propagateTelemetryContextToChildren(): string {
const telemetryEnabled = isTelemetryEnabled();
const orchestratorHarness = telemetryEnabled ? detectOrchestratorHarness() : 'unknown';

Comment on lines +423 to +424
fn detect_orchestrator_harness() -> String {
for key in [

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Similar to the CLI, detect_orchestrator_harness() is executed unconditionally on broker startup, which synchronously spawns ps up to 8 times on Unix platforms. This introduces unnecessary latency on startup when telemetry is disabled.

We should check if telemetry is disabled via environment variables (AGENT_RELAY_TELEMETRY_DISABLED or DO_NOT_TRACK) at the very beginning of the function to return early and avoid the expensive process traversal.

fn detect_orchestrator_harness() -> String {
    if let Ok(val) = std::env::var("AGENT_RELAY_TELEMETRY_DISABLED").or_else(|_| std::env::var("DO_NOT_TRACK")) {
        if val == "1" || val.to_lowercase() == "true" {
            return UNKNOWN_ORCHESTRATOR_HARNESS.to_string();
        }
    }

    for key in [

Comment thread packages/sdk/src/telemetry.ts Outdated
Comment on lines +1 to +6
import {
detectOrchestratorHarness,
initTelemetry,
track,
type CommonProperties,
} from '@agent-relay/telemetry';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Import the shutdown function from @agent-relay/telemetry so that we can register an exit hook to flush pending telemetry events before the process exits.

Suggested change
import {
detectOrchestratorHarness,
initTelemetry,
track,
type CommonProperties,
} from '@agent-relay/telemetry';
import {
detectOrchestratorHarness,
initTelemetry,
track,
shutdown,
type CommonProperties,
} from '@agent-relay/telemetry';

Comment thread packages/sdk/src/telemetry.ts Outdated
Comment on lines +30 to +40
export function initSdkTelemetry(): void {
if (initialized) return;
initialized = true;
initTelemetry({
showNotice: false,
sdkVersion: resolveSdkVersion(),
app: 'sdk',
surface: 'sdk',
orchestratorHarness: orchestratorHarness(),
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Short-lived SDK scripts will likely exit before PostHog has a chance to flush telemetry events (which has a default flushAt: 10 or flushes periodically). Since the SDK does not expose or call shutdown on process exit, telemetry events for short-lived scripts will be lost.

We should register a process.once('beforeExit', ...) listener in initSdkTelemetry to automatically call shutdown() and flush pending events before the process exits.

export function initSdkTelemetry(): void {
  if (initialized) return;
  initialized = true;
  initTelemetry({
    showNotice: false,
    sdkVersion: resolveSdkVersion(),
    app: 'sdk',
    surface: 'sdk',
    orchestratorHarness: orchestratorHarness(),
  });

  if (typeof process !== 'undefined' && typeof process.on === 'function') {
    process.once('beforeExit', () => {
      shutdown().catch(() => {});
    });
  }
}

Comment thread packages/sdk/src/telemetry.ts Outdated
Comment on lines +84 to +106
export async function withSdkMethodTelemetry<T>(method: string, fn: () => Promise<T>): Promise<T> {
const started = Date.now();
try {
const result = await fn();
trackSdkMethodCall({ method, success: true, durationMs: Date.now() - started });
return result;
} catch (error) {
trackSdkMethodCall({ method, success: false, durationMs: Date.now() - started, error });
throw error;
}
}

export async function withSdkWorkflowTelemetry<T>(operation: string, fn: () => Promise<T>): Promise<T> {
const started = Date.now();
try {
const result = await fn();
trackSdkWorkflowRun({ operation, success: true, durationMs: Date.now() - started });
return result;
} catch (error) {
trackSdkWorkflowRun({ operation, success: false, durationMs: Date.now() - started, error });
throw error;
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Telemetry tracking calls (trackSdkMethodCall and trackSdkWorkflowRun) are not wrapped in try/catch blocks inside withSdkMethodTelemetry and withSdkWorkflowTelemetry. If any telemetry initialization or tracking call throws an error (e.g., due to environment issues or PostHog client errors), it will propagate and fail the user's primary SDK method/workflow call.

Telemetry should always fail silently and never disrupt the main application flow. We should wrap the tracking calls in try/catch blocks.

export async function withSdkMethodTelemetry<T>(method: string, fn: () => Promise<T>): Promise<T> {
  const started = Date.now();
  try {
    const result = await fn();
    try {
      trackSdkMethodCall({ method, success: true, durationMs: Date.now() - started });
    } catch {
      // Telemetry failures should never disrupt the main application flow
    }
    return result;
  } catch (error) {
    try {
      trackSdkMethodCall({ method, success: false, durationMs: Date.now() - started, error });
    } catch {
      // Telemetry failures should never disrupt the main application flow
    }
    throw error;
  }
}

export async function withSdkWorkflowTelemetry<T>(operation: string, fn: () => Promise<T>): Promise<T> {
  const started = Date.now();
  try {
    const result = await fn();
    try {
      trackSdkWorkflowRun({ operation, success: true, durationMs: Date.now() - started });
    } catch {
      // Telemetry failures should never disrupt the main application flow
    }
    return result;
  } catch (error) {
    try {
      trackSdkWorkflowRun({ operation, success: false, durationMs: Date.now() - started, error });
    } catch {
      // Telemetry failures should never disrupt the main application flow
    }
    throw error;
  }
}

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f9f18f6819

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/sdk/src/telemetry.ts Outdated
Comment on lines +1 to +6
import {
detectOrchestratorHarness,
initTelemetry,
track,
type CommonProperties,
} from '@agent-relay/telemetry';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep Node-only telemetry out of browser SDK imports

When consumers bundle @agent-relay/sdk for a browser or edge worker, this new static import makes the public SDK entrypoint pull in @agent-relay/telemetry; that package imports posthog-node plus Node builtins such as node:child_process, node:fs, and node:os. Because src/index.ts exports facade, the bundle now fails to resolve those Node-only modules even if telemetry is disabled. Make the telemetry path lazy/optional behind a Node-runtime check or keep it out of the browser-compatible SDK surface.

Useful? React with 👍 / 👎.

Comment thread packages/sdk/src/facade.ts Outdated
Comment on lines +224 to +225
if ('channel' in input && input.channel) {
return base.send(input);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The channel-branch guard incorrectly requires input.channel to be truthy. A valid RelaySendChannelMessageInput with an empty channel string will skip this branch, get cast to the direct-message shape, and then crash when channel-target detection calls string methods on an undefined to field. Route by structural type ('channel' in input) and let downstream validation handle empty channel values. [incorrect condition logic]

Severity Level: Major ⚠️
- ❌ AgentRelay.messages.send crashes on empty channel strings.
- ⚠️ SDK consumers see TypeError before any network request.
- ⚠️ Messaging workflows can fail due to minor input bugs.
Steps of Reproduction ✅
1. In a consumer of the SDK, construct an `AgentRelay` using `new AgentRelay({
workspaceKey: 'test-workspace-key' })` from `packages/sdk/src/agent-relay.ts` (constructor
and properties defined at lines 71–93, `messages` getter at lines 124–129), so that
`this.messaging` is a `RelaycastMessagingClient` and `this.messages` returns
`createEnrichedMessages(this.messaging.messages, ...)` from
`packages/sdk/src/facade.ts:216–221`.

2. Call the high-level send API with a structurally valid channel input but an empty
channel string: `await relay.messages.send({ channel: '', text: 'hello' })`. This
satisfies the `RelaySendChannelMessageInput` shape defined in
`packages/sdk/src/messaging/types.ts:16–22` (`channel: string; text: string; ...`) and
matches the `EnrichedMessages.send` overload in `facade.ts:135–138`.

3. Inside `createEnrichedMessages` in `facade.ts:216–256`, the `enriched.send`
implementation at lines 222–256 executes. The guard `if ('channel' in input &&
input.channel)` at lines 224–225 evaluates to `false` because `input.channel` is the empty
string, so the channel-shaped input is misclassified and execution falls through to the
`RelaySendMessageInput` branch, casting `input` to `sendInput: RelaySendMessageInput` at
line 227 even though it has no `to` field.

4. The next logic assumes a valid `sendInput.to` from `RelaySendMessageInput` (defined at
`facade.ts:96–108`) and eventually calls `isChannelTarget(sendInput.to)` at
`facade.ts:239`. Since `sendInput.to` is `undefined` on the misclassified input,
`isChannelTarget` (defined at `facade.ts:61–63` as `to.startsWith('#')`) throws a
`TypeError: Cannot read properties of undefined (reading 'startsWith')`, causing
`withSdkMethodTelemetry('messages.send', ...)` at `facade.ts:223–256` to record a failed
SDK method and propagate the runtime crash back to the caller instead of routing the
request through `base.messages.send` in `packages/sdk/src/messaging/relaycast.ts:489–501`.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** packages/sdk/src/facade.ts
**Line:** 224:225
**Comment:**
	*Incorrect Condition Logic: The channel-branch guard incorrectly requires `input.channel` to be truthy. A valid `RelaySendChannelMessageInput` with an empty channel string will skip this branch, get cast to the direct-message shape, and then crash when channel-target detection calls string methods on an undefined `to` field. Route by structural type (`'channel' in input`) and let downstream validation handle empty channel values.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines +362 to +363
if base == "zed" || lower.contains("zed") {
return Some("zed");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The broker's harness inference also classifies any command containing zed as Zed, which creates false positives for unrelated process names and pollutes telemetry dimensions. Match only normalized executable names (or path segments) instead of generic substring checks. [incorrect condition logic]

Severity Level: Major ⚠️
- ⚠️ Broker telemetry mislabels arbitrary parents as Zed harness.
- ⚠️ Telemetry dashboards overreport Zed-driven broker usage.
Steps of Reproduction ✅
1. Observe that the broker CLI entrypoint `run()` in `crates/broker/src/cli/mod.rs:11-20`
constructs a telemetry client via `let telemetry = TelemetryClient::new();` (line ~114 in
the file, as shown in the repo code graph).

2. In `TelemetryClient::new` ( `crates/broker/src/telemetry.rs:540-599` ), the struct
field `orchestrator_harness` is initialized by calling `detect_orchestrator_harness()`
(line 26 of that snippet).

3. `detect_orchestrator_harness()` ( `crates/broker/src/telemetry.rs:164-179` ) falls back
to `detect_process_orchestrator_harness()` when no explicit harness env var is set; on
Unix, `detect_process_orchestrator_harness()` walks parent PIDs and calls
`lookup_process_info()` / `infer_harness_from_command()` for each parent (lines 134-147).

4. Inside `infer_harness_from_command()` ( `crates/broker/src/telemetry.rs:60-107` ), the
`zed` branch is implemented as `if base == "zed" || lower.contains("zed") { return
Some("zed"); }` (lines 362-363 in the current file), so a parent process command like
`/usr/bin/analyzed` (base `analyzed`, but `lower` contains the substring `zed`) is
misclassified as the Zed harness; this value is then emitted on every broker telemetry
event via the `orchestrator_harness` property merged in `TelemetryClient::track` (lines
44-57 in the `540-599` snippet).

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** crates/broker/src/telemetry.rs
**Line:** 362:363
**Comment:**
	*Incorrect Condition Logic: The broker's harness inference also classifies any command containing `zed` as Zed, which creates false positives for unrelated process names and pollutes telemetry dimensions. Match only normalized executable names (or path segments) instead of generic substring checks.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment thread packages/sdk/src/telemetry.ts Outdated
Comment on lines +11 to +13
function resolveSdkVersion(): string | undefined {
const version = process.env.AGENT_RELAY_SDK_VERSION?.trim();
return version || undefined;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: resolveSdkVersion only reads AGENT_RELAY_SDK_VERSION, so SDK telemetry emitted outside the CLI path usually has no sdk_version; then initTelemetry falls back to the telemetry package version for agent_relay_version, producing incorrect version attribution in dashboards. Resolve the SDK package version directly (or inject it at build time) instead of relying only on an env var. [logic error]

Severity Level: Major ⚠️
- ⚠️ SDK telemetry events tagged with telemetry package version.
- ⚠️ Dashboards cannot accurately segment by SDK version.
Steps of Reproduction ✅
1. In a Node application using the SDK, call any facade method that is wrapped with
telemetry, e.g. `createEnrichedMessages(...).send(...)` in
`packages/sdk/src/facade.ts:222-247`, which internally wraps the send logic in
`withSdkMethodTelemetry('messages.send', ...)` (line 223).

2. `withSdkMethodTelemetry` in `packages/sdk/src/telemetry.ts:84-93` calls
`trackSdkMethodCall`, which first calls `initSdkTelemetry()` (lines 30-40) before emitting
the event.

3. `initSdkTelemetry()` calls `initTelemetry({ sdkVersion: resolveSdkVersion(), app:
'sdk', surface: 'sdk', orchestratorHarness: orchestratorHarness() })` (lines 33-39). In a
typical non-CLI SDK integration, `process.env.AGENT_RELAY_SDK_VERSION` is not set, so
`resolveSdkVersion()` (lines 11-13) trims the env var, gets `undefined`, and returns
`undefined`.

4. In `packages/telemetry/src/client.ts:60-75`, `buildCommonProperties` computes the
primary `agent_relay_version` as `versions.cliVersion ?? versions.brokerVersion ??
versions.sdkVersion ?? getFallbackVersion()`. With `cliVersion`, `brokerVersion`, and
`sdkVersion` all undefined (because only the SDK is in use and `AGENT_RELAY_SDK_VERSION`
was unset), `getFallbackVersion()` is used instead (lines 45-57), which the comments note
resolves the *telemetry package* `package.json`. As a result, SDK events are tagged with
the telemetry package version in `agent_relay_version`, and `sdk_version` is absent,
producing incorrect version attribution in dashboards for any SDK-only usage that is not
launched via the CLI.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** packages/sdk/src/telemetry.ts
**Line:** 11:13
**Comment:**
	*Logic Error: `resolveSdkVersion` only reads `AGENT_RELAY_SDK_VERSION`, so SDK telemetry emitted outside the CLI path usually has no `sdk_version`; then `initTelemetry` falls back to the telemetry package version for `agent_relay_version`, producing incorrect version attribution in dashboards. Resolve the SDK package version directly (or inject it at build time) instead of relying only on an env var.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

if (base === 'droid' || lower.includes('droid')) return 'droid';
if (base === 'amp' || normalized.includes('/amp')) return 'amp';
if (lower.includes('copilot')) return 'github-copilot';
if (base === 'zed' || lower.includes('zed')) return 'zed';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The zed detection uses a raw substring match, so unrelated process names containing zed (for example analyzed or dozed) will be misclassified as the Zed harness. Restrict matching to executable/base-name boundaries instead of generic substring matching. [incorrect condition logic]

Severity Level: Major ⚠️
- ⚠️ Node telemetry mislabels arbitrary parents as Zed harness.
- ⚠️ Harness usage metrics overreport Zed in dashboards.
Steps of Reproduction ✅
1. `detectOrchestratorHarness()` in
`packages/telemetry/src/orchestrator-harness.ts:82-107` is used by the telemetry client
via `buildCommonProperties` in `packages/telemetry/src/client.ts:60-75`, where
`orchestrator_harness` is set to `versions.orchestratorHarness ??
detectOrchestratorHarness() ?? UNKNOWN_ORCHESTRATOR_HARNESS` (lines 94-96) whenever the
caller did not explicitly supply a harness.

2. In a Node process (e.g. the CLI or any other consumer using `@agent-relay/telemetry`
directly), `detectOrchestratorHarness()` first checks for explicit env overrides, then
walks parent PIDs using a `processLookup` function (defaulting to `lookupProcessInfo`) and
passes each parent's command string to `inferHarnessFromCommand()` (lines 89-100 in
`orchestrator-harness.ts`).

3. `inferHarnessFromCommand()` (lines 36-54) normalizes the command and computes `base`,
but the `zed` detection branch is implemented as `if (base === 'zed' ||
lower.includes('zed')) return 'zed';` (line 52), so a command like `"/usr/bin/analyzed"`
or `"my-zedless-tool"`—where `base` is not `'zed'` but `lower` contains the substring
`'zed'`—will be incorrectly classified as the Zed harness.

4. When such a parent process exists, `detectOrchestratorHarness()` returns `'zed'`, and
`buildCommonProperties` propagates this into the `orchestrator_harness` property for all
telemetry events emitted by that process, leading to misclassified harness telemetry
despite no actual Zed harness being involved.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** packages/telemetry/src/orchestrator-harness.ts
**Line:** 52:52
**Comment:**
	*Incorrect Condition Logic: The `zed` detection uses a raw substring match, so unrelated process names containing `zed` (for example `analyzed` or `dozed`) will be misclassified as the Zed harness. Restrict matching to executable/base-name boundaries instead of generic substring matching.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@codeant-ai

codeant-ai Bot commented Jun 3, 2026

Copy link
Copy Markdown

CodeAnt AI finished reviewing your PR.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
packages/telemetry/src/client.ts (1)

76-93: 💤 Low value

Consider extracting the app/surface inference logic to reduce duplication.

The app and surface fields use identical inference logic (lines 76-93). While the duplication is manageable, extracting a helper could improve maintainability.

♻️ Optional refactor to reduce duplication
+function inferComponent(
+  explicit: string | undefined,
+  cliVersion: string | undefined,
+  brokerVersion: string | undefined,
+  sdkVersion: string | undefined
+): string {
+  return (
+    explicit ??
+    (cliVersion ? 'cli' : brokerVersion ? 'broker' : sdkVersion ? 'sdk' : 'unknown')
+  );
+}
+
 function buildCommonProperties(versions: {
   cliVersion?: string;
   sdkVersion?: string;
   brokerVersion?: string;
   app?: string;
   surface?: string;
   orchestratorHarness?: string;
 }): CommonProperties {
   const primary =
     versions.cliVersion ?? versions.brokerVersion ?? versions.sdkVersion ?? getFallbackVersion();

   return {
-    app:
-      versions.app ??
-      (versions.cliVersion
-        ? 'cli'
-        : versions.brokerVersion
-          ? 'broker'
-          : versions.sdkVersion
-            ? 'sdk'
-            : 'unknown'),
-    surface:
-      versions.surface ??
-      (versions.cliVersion
-        ? 'cli'
-        : versions.brokerVersion
-          ? 'broker'
-          : versions.sdkVersion
-            ? 'sdk'
-            : 'unknown'),
+    app: inferComponent(versions.app, versions.cliVersion, versions.brokerVersion, versions.sdkVersion),
+    surface: inferComponent(versions.surface, versions.cliVersion, versions.brokerVersion, versions.sdkVersion),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/telemetry/src/client.ts` around lines 76 - 93, Duplicate inference
logic for app and surface should be extracted into a small helper to improve
maintainability: add a helper function (e.g., inferAppOrSurface or inferVariant)
that takes the versions object and returns versions.app ?? (versions.cliVersion
? 'cli' : versions.brokerVersion ? 'broker' : versions.sdkVersion ? 'sdk' :
'unknown'), then replace the inline expressions used for both app and surface
with calls to this helper; ensure the helper is colocated with the telemetry
client code and preserves the exact precedence/values and TypeScript types used
by the existing code.
packages/cloud/src/telemetry-headers.ts (1)

7-13: ⚡ Quick win

Centralize telemetry env-key constants to avoid CLI/cloud drift

AGENT_RELAY_CLIENT_ID_ENV, TELEMETRY_SURFACE_ENV, and TELEMETRY_CLIENT_ENV are duplicated string literals in both packages/cloud/src/telemetry-headers.ts and packages/cli/src/cli/bootstrap.ts. Centralize these env-key constants (e.g., export from @agent-relay/telemetry) and import them in both places to prevent silent mismatches if one side changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cloud/src/telemetry-headers.ts` around lines 7 - 13, Centralize the
duplicated telemetry env-key constants by exporting AGENT_RELAY_CLIENT_ID_ENV,
TELEMETRY_SURFACE_ENV, and TELEMETRY_CLIENT_ENV from a single shared module
(e.g., add exports in `@agent-relay/telemetry`), then replace the hard-coded
declarations in packages/cloud/src/telemetry-headers.ts (currently declaring
AGENT_RELAY_CLIENT_ID_ENV, TELEMETRY_SURFACE_ENV, TELEMETRY_CLIENT_ENV) and the
duplicates in packages/cli/src/cli/bootstrap.ts with imports from that shared
module; remove the local constant declarations and update any references to use
the imported symbols so both cloud and CLI use the same authoritative values.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/cloud/src/telemetry-headers.ts`:
- Around line 26-29: The function isTelemetryDisabledByEnv currently uses
nullish coalescing between AGENT_RELAY_TELEMETRY_DISABLED and DO_NOT_TRACK which
causes DO_NOT_TRACK to be ignored when AGENT_RELAY_TELEMETRY_DISABLED is set to
a non-truthy value; change isTelemetryDisabledByEnv to use an OR-based truthy
check (e.g., evaluate each env var with the same truthiness rules used in
packages/telemetry/src/config.ts or call its isTruthyEnv helper) so that
telemetry is disabled when either AGENT_RELAY_TELEMETRY_DISABLED or DO_NOT_TRACK
is truthy.

In `@packages/sdk/src/telemetry.ts`:
- Around line 50-82: The telemetry helpers trackSdkMethodCall and
trackSdkWorkflowRun must never throw; wrap the calls to initSdkTelemetry(),
sdkCommonOverrides()/detectOrchestratorHarness(), and track(...) inside a
try/catch that swallows any exceptions (optionally logging them to a
non-throwing debug logger) so telemetry failures cannot change business results;
specifically, update both trackSdkMethodCall and trackSdkWorkflowRun to call
initSdkTelemetry(), build errorClass, call sdkCommonOverrides() and track(...)
all inside a single try block and catch any error to suppress it (do not
rethrow), ensuring initTelemetry/detectOrchestratorHarness/track errors are
contained.

---

Nitpick comments:
In `@packages/cloud/src/telemetry-headers.ts`:
- Around line 7-13: Centralize the duplicated telemetry env-key constants by
exporting AGENT_RELAY_CLIENT_ID_ENV, TELEMETRY_SURFACE_ENV, and
TELEMETRY_CLIENT_ENV from a single shared module (e.g., add exports in
`@agent-relay/telemetry`), then replace the hard-coded declarations in
packages/cloud/src/telemetry-headers.ts (currently declaring
AGENT_RELAY_CLIENT_ID_ENV, TELEMETRY_SURFACE_ENV, TELEMETRY_CLIENT_ENV) and the
duplicates in packages/cli/src/cli/bootstrap.ts with imports from that shared
module; remove the local constant declarations and update any references to use
the imported symbols so both cloud and CLI use the same authoritative values.

In `@packages/telemetry/src/client.ts`:
- Around line 76-93: Duplicate inference logic for app and surface should be
extracted into a small helper to improve maintainability: add a helper function
(e.g., inferAppOrSurface or inferVariant) that takes the versions object and
returns versions.app ?? (versions.cliVersion ? 'cli' : versions.brokerVersion ?
'broker' : versions.sdkVersion ? 'sdk' : 'unknown'), then replace the inline
expressions used for both app and surface with calls to this helper; ensure the
helper is colocated with the telemetry client code and preserves the exact
precedence/values and TypeScript types used by the existing code.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c7d69eda-e051-4dc4-bce9-ffb4b379d18f

📥 Commits

Reviewing files that changed from the base of the PR and between 3be269e and 6e5d793.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (21)
  • .agentworkforce/trajectories/completed/2026-06/traj_6kef2z1redhb/summary.md
  • .agentworkforce/trajectories/completed/2026-06/traj_6kef2z1redhb/trajectory.json
  • CHANGELOG.md
  • crates/broker/src/telemetry.rs
  • packages/cli/src/cli/bootstrap.ts
  • packages/cli/src/cli/entrypoint.test.ts
  • packages/cloud/src/api-client.ts
  • packages/cloud/src/auth.test.ts
  • packages/cloud/src/auth.ts
  • packages/cloud/src/telemetry-headers.ts
  • packages/sdk/package.json
  • packages/sdk/src/agent-relay.ts
  • packages/sdk/src/facade.ts
  • packages/sdk/src/telemetry.ts
  • packages/sdk/tsconfig.build.json
  • packages/sdk/tsconfig.json
  • packages/telemetry/src/client.ts
  • packages/telemetry/src/events.ts
  • packages/telemetry/src/index.ts
  • packages/telemetry/src/orchestrator-harness.test.ts
  • packages/telemetry/src/orchestrator-harness.ts

Comment on lines +26 to +29
function isTelemetryDisabledByEnv(env: NodeJS.ProcessEnv): boolean {
const disabled = env.AGENT_RELAY_TELEMETRY_DISABLED ?? env.DO_NOT_TRACK;
return disabled === '1' || disabled?.toLowerCase() === 'true';
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect the canonical env opt-out implementation to compare semantics.
rg -nP -C6 'isDisabledByEnv' --type=ts -g 'packages/telemetry/src/config.ts'

Repository: AgentWorkforce/relay

Length of output: 1639


Fix env opt-out semantics to match packages/telemetry/src/config.ts.

isTelemetryDisabledByEnv in packages/cloud/src/telemetry-headers.ts uses env.AGENT_RELAY_TELEMETRY_DISABLED ?? env.DO_NOT_TRACK, so if AGENT_RELAY_TELEMETRY_DISABLED is set to a non-truthy value (e.g. '0'/'false'), it will ignore DO_NOT_TRACK='true'. In packages/telemetry/src/config.ts, isDisabledByEnv() disables when either env var is truthy (isTruthyEnv(...) || isTruthyEnv(...)).

Reuse the canonical logic (or align the cloud check to an OR-based evaluation over both env vars).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cloud/src/telemetry-headers.ts` around lines 26 - 29, The function
isTelemetryDisabledByEnv currently uses nullish coalescing between
AGENT_RELAY_TELEMETRY_DISABLED and DO_NOT_TRACK which causes DO_NOT_TRACK to be
ignored when AGENT_RELAY_TELEMETRY_DISABLED is set to a non-truthy value; change
isTelemetryDisabledByEnv to use an OR-based truthy check (e.g., evaluate each
env var with the same truthiness rules used in packages/telemetry/src/config.ts
or call its isTruthyEnv helper) so that telemetry is disabled when either
AGENT_RELAY_TELEMETRY_DISABLED or DO_NOT_TRACK is truthy.

Comment thread packages/sdk/src/telemetry.ts Outdated
Comment on lines +50 to +82
export function trackSdkMethodCall(input: {
method: string;
success: boolean;
durationMs: number;
error?: unknown;
}): void {
initSdkTelemetry();
const errorClass = input.error === undefined ? undefined : errorClassName(input.error);
track('sdk_method_call', {
method: input.method,
success: input.success,
duration_ms: input.durationMs,
...(errorClass ? { error_class: errorClass } : {}),
...sdkCommonOverrides(),
});
}

export function trackSdkWorkflowRun(input: {
operation: string;
success: boolean;
durationMs: number;
error?: unknown;
}): void {
initSdkTelemetry();
const errorClass = input.error === undefined ? undefined : errorClassName(input.error);
track('sdk_workflow_run', {
operation: input.operation,
success: input.success,
duration_ms: input.durationMs,
...(errorClass ? { error_class: errorClass } : {}),
...sdkCommonOverrides(),
});
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Telemetry emission must not be able to break SDK operations.

trackSdkMethodCall / trackSdkWorkflowRun invoke initSdkTelemetry()initTelemetry(...), sdkCommonOverrides()detectOrchestratorHarness(), and track(...) with no error guard. In the wrappers (Lines 84-106) these run after await fn() succeeds, so a throw here discards a successful result; and in the catch branch a throw masks the user's real error before the throw error rethrow. Telemetry is a side-effect and should never alter business-logic outcomes.

🛡️ Proposed fix: swallow telemetry failures at the emit boundary
 export function trackSdkMethodCall(input: {
   method: string;
   success: boolean;
   durationMs: number;
   error?: unknown;
 }): void {
-  initSdkTelemetry();
-  const errorClass = input.error === undefined ? undefined : errorClassName(input.error);
-  track('sdk_method_call', {
-    method: input.method,
-    success: input.success,
-    duration_ms: input.durationMs,
-    ...(errorClass ? { error_class: errorClass } : {}),
-    ...sdkCommonOverrides(),
-  });
+  try {
+    initSdkTelemetry();
+    const errorClass = input.error === undefined ? undefined : errorClassName(input.error);
+    track('sdk_method_call', {
+      method: input.method,
+      success: input.success,
+      duration_ms: input.durationMs,
+      ...(errorClass ? { error_class: errorClass } : {}),
+      ...sdkCommonOverrides(),
+    });
+  } catch {
+    // Telemetry failures must never affect SDK behavior.
+  }
 }

 export function trackSdkWorkflowRun(input: {
   operation: string;
   success: boolean;
   durationMs: number;
   error?: unknown;
 }): void {
-  initSdkTelemetry();
-  const errorClass = input.error === undefined ? undefined : errorClassName(input.error);
-  track('sdk_workflow_run', {
-    operation: input.operation,
-    success: input.success,
-    duration_ms: input.durationMs,
-    ...(errorClass ? { error_class: errorClass } : {}),
-    ...sdkCommonOverrides(),
-  });
+  try {
+    initSdkTelemetry();
+    const errorClass = input.error === undefined ? undefined : errorClassName(input.error);
+    track('sdk_workflow_run', {
+      operation: input.operation,
+      success: input.success,
+      duration_ms: input.durationMs,
+      ...(errorClass ? { error_class: errorClass } : {}),
+      ...sdkCommonOverrides(),
+    });
+  } catch {
+    // Telemetry failures must never affect SDK behavior.
+  }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/sdk/src/telemetry.ts` around lines 50 - 82, The telemetry helpers
trackSdkMethodCall and trackSdkWorkflowRun must never throw; wrap the calls to
initSdkTelemetry(), sdkCommonOverrides()/detectOrchestratorHarness(), and
track(...) inside a try/catch that swallows any exceptions (optionally logging
them to a non-throwing debug logger) so telemetry failures cannot change
business results; specifically, update both trackSdkMethodCall and
trackSdkWorkflowRun to call initSdkTelemetry(), build errorClass, call
sdkCommonOverrides() and track(...) all inside a single try block and catch any
error to suppress it (do not rethrow), ensuring
initTelemetry/detectOrchestratorHarness/track errors are contained.

@agent-relay-code

Copy link
Copy Markdown
Contributor

⚠️ pr-reviewer did not push — the PR branch advanced during the review, so fixes were withheld to avoid overwriting newer commits. Re-trigger the review once the branch settles. The notes below are advisory and were not pushed.

Reviewed PR #1033 and fixed one concrete issue.

Changed:

  • packages/cloud/src/telemetry-headers.ts: managed Agent Relay telemetry headers are now stripped before sanitized env-derived values are applied, so stale/caller-provided telemetry identity headers are not forwarded when telemetry is disabled or no client id is available.
  • packages/cloud/src/auth.test.ts: added coverage for stripping caller-provided telemetry headers when telemetry is disabled.

Validation:

  • npm -w packages/cloud run build passed.
  • npm -w packages/sdk run check passed.
  • npm -w packages/telemetry run build && npm -w packages/sdk run build passed.
  • npx prettier --check ... passed.
  • Runtime assertion against built packages/cloud/dist/telemetry-headers.js passed.
  • Vitest could not run in this local environment: node_modules is missing ESM files advertised by dependencies (pathe/dist/index.mjs, then magic-string/dist/magic-string.es.mjs) under Node v25.6.0/npm 11.8.0. This is an environment/install issue, not a source failure.
  • Rust broker tests could not run because cargo is not installed.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 issues found across 22 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/cloud/src/telemetry-headers.ts">

<violation number="1" location="packages/cloud/src/telemetry-headers.ts:27">
P2: Empty `AGENT_RELAY_TELEMETRY_DISABLED` suppresses `DO_NOT_TRACK` fallback, which can bypass telemetry opt-out.</violation>

<violation number="2" location="packages/cloud/src/telemetry-headers.ts:58">
P2: Version fallback is blocked when CLI version env var is empty, causing dropped telemetry version context.</violation>
</file>

<file name="packages/telemetry/src/orchestrator-harness.ts">

<violation number="1" location="packages/telemetry/src/orchestrator-harness.ts:44">
P2: Substring-based harness detection can misclassify unrelated commands as `cursor` and skew telemetry labels.</violation>
</file>

<file name=".agentworkforce/trajectories/completed/2026-06/traj_6kef2z1redhb/summary.md">

<violation number="1" location=".agentworkforce/trajectories/completed/2026-06/traj_6kef2z1redhb/summary.md:1">
P3: Typo in heading: "Rope" should be "Route" to match the PR title and all other references in the document.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

maxLength: 80,
pattern: HEADER_VALUE_ALLOWED,
});
const version = sanitizeHeaderValue(env.AGENT_RELAY_CLI_VERSION ?? env.AGENT_RELAY_SDK_VERSION, {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Version fallback is blocked when CLI version env var is empty, causing dropped telemetry version context.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cloud/src/telemetry-headers.ts, line 58:

<comment>Version fallback is blocked when CLI version env var is empty, causing dropped telemetry version context.</comment>

<file context>
@@ -0,0 +1,81 @@
+    maxLength: 80,
+    pattern: HEADER_VALUE_ALLOWED,
+  });
+  const version = sanitizeHeaderValue(env.AGENT_RELAY_CLI_VERSION ?? env.AGENT_RELAY_SDK_VERSION, {
+    maxLength: 48,
+    pattern: HEADER_VALUE_ALLOWED,
</file context>
Suggested change
const version = sanitizeHeaderValue(env.AGENT_RELAY_CLI_VERSION ?? env.AGENT_RELAY_SDK_VERSION, {
const version = sanitizeHeaderValue(env.AGENT_RELAY_CLI_VERSION?.trim() || env.AGENT_RELAY_SDK_VERSION?.trim(), {

}

function isTelemetryDisabledByEnv(env: NodeJS.ProcessEnv): boolean {
const disabled = env.AGENT_RELAY_TELEMETRY_DISABLED ?? env.DO_NOT_TRACK;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Empty AGENT_RELAY_TELEMETRY_DISABLED suppresses DO_NOT_TRACK fallback, which can bypass telemetry opt-out.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cloud/src/telemetry-headers.ts, line 27:

<comment>Empty `AGENT_RELAY_TELEMETRY_DISABLED` suppresses `DO_NOT_TRACK` fallback, which can bypass telemetry opt-out.</comment>

<file context>
@@ -0,0 +1,81 @@
+}
+
+function isTelemetryDisabledByEnv(env: NodeJS.ProcessEnv): boolean {
+  const disabled = env.AGENT_RELAY_TELEMETRY_DISABLED ?? env.DO_NOT_TRACK;
+  return disabled === '1' || disabled?.toLowerCase() === 'true';
+}
</file context>
Suggested change
const disabled = env.AGENT_RELAY_TELEMETRY_DISABLED ?? env.DO_NOT_TRACK;
const disabled = env.AGENT_RELAY_TELEMETRY_DISABLED?.trim() || env.DO_NOT_TRACK?.trim();


if (base === 'claude' || lower.includes('claude-code')) return 'claude-code';
if (base === 'codex' || normalized.includes('/codex')) return 'codex';
if (base === 'cursor' || base === 'cursor-agent' || lower.includes('cursor')) return 'cursor';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Substring-based harness detection can misclassify unrelated commands as cursor and skew telemetry labels.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/telemetry/src/orchestrator-harness.ts, line 44:

<comment>Substring-based harness detection can misclassify unrelated commands as `cursor` and skew telemetry labels.</comment>

<file context>
@@ -0,0 +1,107 @@
+
+  if (base === 'claude' || lower.includes('claude-code')) return 'claude-code';
+  if (base === 'codex' || normalized.includes('/codex')) return 'codex';
+  if (base === 'cursor' || base === 'cursor-agent' || lower.includes('cursor')) return 'cursor';
+  if (base === 'gemini' || base === 'gemini-cli' || lower.includes('gemini-cli')) return 'gemini-cli';
+  if (base === 'aider' || lower.includes('aider')) return 'aider';
</file context>

Comment thread packages/sdk/src/telemetry.ts Outdated
@@ -0,0 +1,45 @@
# Trajectory: Rope telemetry through CLI SDK and hosted backend

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Typo in heading: "Rope" should be "Route" to match the PR title and all other references in the document.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .agentworkforce/trajectories/completed/2026-06/traj_6kef2z1redhb/summary.md, line 1:

<comment>Typo in heading: "Rope" should be "Route" to match the PR title and all other references in the document.</comment>

<file context>
@@ -0,0 +1,45 @@
+# Trajectory: Rope telemetry through CLI SDK and hosted backend
+
+> **Status:** ✅ Completed
</file context>
Suggested change
# Trajectory: Rope telemetry through CLI SDK and hosted backend
# Trajectory: Route telemetry through CLI SDK and hosted backend

@agent-relay-code

Copy link
Copy Markdown
Contributor

Fixed the PR-local breakage I found:

  • Added a package-local Vitest alias so @agent-relay/sdk tests resolve the new @agent-relay/telemetry workspace dependency from source.
  • Updated the SDK RelayCast mock to be constructable under Vitest 4.

Verification run locally:

  • npm run typecheck
  • npm --prefix packages/sdk test -- --run
  • targeted PR Vitest tests for telemetry/cloud/cli
  • npx prettier --check ...
  • npm test passed: 58 files passed, 832 tests passed

Rust broker tests could not be run directly because this container has no Rust toolchain; the repo’s npm test build step also skipped Rust for that reason.

@agent-relay-code

Copy link
Copy Markdown
Contributor

⚠️ pr-reviewer push failed (exit 128) — fixes were not applied to the PR. The notes below are advisory and were not pushed.

Fixed the PR-local breakage I found:

  • Added a package-local Vitest alias so @agent-relay/sdk tests resolve the new @agent-relay/telemetry workspace dependency from source.
  • Updated the SDK RelayCast mock to be constructable under Vitest 4.

Verification run locally:

  • npm run typecheck
  • npm --prefix packages/sdk test -- --run
  • targeted PR Vitest tests for telemetry/cloud/cli
  • npx prettier --check ...
  • npm test passed: 58 files passed, 832 tests passed

Rust broker tests could not be run directly because this container has no Rust toolchain; the repo’s npm test build step also skipped Rust for that reason.

@agent-relay-code

Copy link
Copy Markdown
Contributor

Reviewed and fixed PR #1033 locally.

Changes made:

  • Restored telemetry first-run notice behavior in packages/telemetry/src/client.ts so missing PostHog config does not suppress the opt-out notice.
  • Added regression coverage in packages/telemetry/src/client.test.ts.
  • Fixed the SDK RelayCast test mock to be constructible after telemetry wrapping touched the workspace creation path.

Validated:

  • npx vitest run packages/telemetry/src/client.test.ts packages/telemetry/src/orchestrator-harness.test.ts packages/cloud/src/auth.test.ts --run
  • npm --prefix packages/sdk test -- --run
  • npm run typecheck
  • npx prettier --check ...

Cargo was not available in the container, so I could not run Rust telemetry tests locally.

@agent-relay-code

Copy link
Copy Markdown
Contributor

⚠️ pr-reviewer did not push — the PR branch advanced during the review, so fixes were withheld to avoid overwriting newer commits. Re-trigger the review once the branch settles. The notes below are advisory and were not pushed.

Reviewed and fixed PR #1033 locally.

Changes made:

  • Restored telemetry first-run notice behavior in packages/telemetry/src/client.ts so missing PostHog config does not suppress the opt-out notice.
  • Added regression coverage in packages/telemetry/src/client.test.ts.
  • Fixed the SDK RelayCast test mock to be constructible after telemetry wrapping touched the workspace creation path.

Validated:

  • npx vitest run packages/telemetry/src/client.test.ts packages/telemetry/src/orchestrator-harness.test.ts packages/cloud/src/auth.test.ts --run
  • npm --prefix packages/sdk test -- --run
  • npm run typecheck
  • npx prettier --check ...

Cargo was not available in the container, so I could not run Rust telemetry tests locally.

@codeant-ai

codeant-ai Bot commented Jun 3, 2026

Copy link
Copy Markdown

CodeAnt AI is running Incremental review

@codeant-ai codeant-ai Bot added size:XL This PR changes 500-999 lines, ignoring generated files and removed size:XXL This PR changes 1000+ lines, ignoring generated files labels Jun 3, 2026
@codeant-ai

codeant-ai Bot commented Jun 3, 2026

Copy link
Copy Markdown

CodeAnt AI Incremental review completed.

@agent-relay-code

Copy link
Copy Markdown
Contributor

⚠️ pr-reviewer did not push — the PR branch advanced during the review, so fixes were withheld to avoid overwriting newer commits. Re-trigger the review once the branch settles. The notes below are advisory and were not pushed.

Reviewed PR #1033 and fixed the local breakages I found:

  • Added SDK Vitest alias for @agent-relay/telemetry.
  • Added packages/telemetry/vitest.config.ts so its new tests run from the package.
  • Added missing root Vitest alias for @agent-relay/harness-driver.
  • Fixed the SDK RelayCast mock to be constructible under Vitest 4.

Local checks passed:

  • npm run typecheck
  • npm --prefix packages/sdk test
  • npm --prefix packages/telemetry test
  • npx vitest run packages/cli/src/cli/entrypoint.test.ts packages/cloud/src/auth.test.ts packages/telemetry/src/orchestrator-harness.test.ts
  • npm --prefix packages/cli run build

Rust broker tests were not run because Cargo is not installed in this environment.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/cli/src/cli/commands/setup.ts (1)

75-75: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update stale “anonymous telemetry” wording in command help.

Line 75 still says “Manage anonymous telemetry…”, which conflicts with the new “usage telemetry” + distinct ID wording shown in this command.

Suggested patch
-    .description('Manage anonymous telemetry (enable/disable/status)')
+    .description('Manage usage telemetry (enable/disable/status)')
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/cli/commands/setup.ts` at line 75, Update the command
description string to replace the outdated "anonymous telemetry" phrasing with
the new terminology used elsewhere ("usage telemetry" and the distinct ID).
Locate the command builder where .description('Manage anonymous telemetry
(enable/disable/status)') is set (in the setup command) and change the text to
something like "Manage usage telemetry and distinct ID (enable/disable/status)"
so the help output matches the updated UI/UX language.
♻️ Duplicate comments (1)
packages/cloud/src/telemetry-headers.ts (1)

26-29: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Honor DO_NOT_TRACK independently of AGENT_RELAY_TELEMETRY_DISABLED.

Line 27 currently uses ??, so AGENT_RELAY_TELEMETRY_DISABLED='0' can suppress DO_NOT_TRACK='true'. That can still emit telemetry despite an explicit DNT signal.

Proposed fix
 function isTelemetryDisabledByEnv(env: NodeJS.ProcessEnv): boolean {
-  const disabled = env.AGENT_RELAY_TELEMETRY_DISABLED ?? env.DO_NOT_TRACK;
-  return disabled === '1' || disabled?.toLowerCase() === 'true';
+  const isTruthy = (value: string | undefined): boolean =>
+    value === '1' || value?.toLowerCase() === 'true';
+
+  return isTruthy(env.AGENT_RELAY_TELEMETRY_DISABLED) || isTruthy(env.DO_NOT_TRACK);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cloud/src/telemetry-headers.ts` around lines 26 - 29, The function
isTelemetryDisabledByEnv currently uses the nullish coalescing operator so
AGENT_RELAY_TELEMETRY_DISABLED='0' can block DO_NOT_TRACK='true'; update
isTelemetryDisabledByEnv to evaluate AGENT_RELAY_TELEMETRY_DISABLED and
DO_NOT_TRACK independently (e.g., check both values and return true if either
equals '1' or case-insensitive 'true'), referencing the function name
isTelemetryDisabledByEnv and the env keys AGENT_RELAY_TELEMETRY_DISABLED and
DO_NOT_TRACK.
🧹 Nitpick comments (3)
CHANGELOG.md (3)

35-35: ⚡ Quick win

Reconsider including internal telemetry infrastructure changes.

This entry describes backend telemetry implementation details rather than user-visible changes. The guidelines specify omitting internal notes and implementation details. Unless there's a direct user-facing benefit (e.g., "Telemetry now persists across CLI restarts"), consider removing this entry or rewriting it to focus on observable user impact.

As per coding guidelines: "Changelog entries should be concise and impact-first, with one short bullet per user-visible change. Omit issue/PR links, internal notes, and implementation details."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` at line 35, This changelog entry exposes internal telemetry
implementation; remove or rewrite it to be user-facing and concise: either
delete the `agent-relay` / Relaycast telemetry bullet entirely or replace it
with a one-line, impact-first statement that users care about (e.g., "CLI and
SDK requests are now distinguished in backend telemetry so support can better
diagnose usage") without mentioning internal systems like `agent-relay`,
`Relaycast`, or implementation details about client identity context. Ensure the
final bullet follows the project's rule of one short, user-visible change per
line.

49-49: ⚡ Quick win

Remove implementation details about attribution mechanism.

The second clause "SDK/API attribution uses Relaycast origin metadata instead" describes internal implementation details. Consider removing everything after "telemetry`" to keep the entry focused on the user-visible change (dependency removal).

✂️ Suggested simplification
-- `@agent-relay/sdk` no longer emits client-side analytics or depends on `@agent-relay/telemetry`; SDK/API attribution uses Relaycast origin metadata instead.
+- `@agent-relay/sdk` no longer emits client-side analytics or depends on `@agent-relay/telemetry`.

As per coding guidelines: "Changelog entries should be concise and impact-first, with one short bullet per user-visible change. Omit issue/PR links, internal notes, and implementation details."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` at line 49, Update the CHANGELOG entry by removing the internal
implementation clause so the bullet reads only that `@agent-relay/sdk` no longer
emits client-side analytics or depends on `@agent-relay/telemetry`; delete the
trailing phrase "SDK/API attribution uses Relaycast origin metadata instead" and
leave the concise, user-facing statement about dependency removal.

48-48: ⚡ Quick win

Remove internal build process details.

This entry describes an internal build validation change that isn't user-visible. The guidelines specify focusing on user-visible changes only. Unless this build change affects what users can install or how the packages behave, this should be removed from the changelog.

As per coding guidelines: "Changelog entries should be concise and impact-first, with one short bullet per user-visible change. Omit issue/PR links, internal notes, and implementation details."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` at line 48, The changelog contains an internal build-process
detail ("Root builds now validate the simplified core package set: config,
utils, SDK, harness-driver, harnesses, and CLI.") that must be removed or
replaced with a user-visible impact statement; edit CHANGELOG.md to delete that
line (or rewrite it as a concise, impact-first bullet describing any user-facing
change such as "Simplified core packages to improve install size/stability" if
there is an actual user impact) so the entry only contains user-visible changes
and omits implementation/internal notes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/cli/src/cli/commands/setup.ts`:
- Line 75: Update the command description string to replace the outdated
"anonymous telemetry" phrasing with the new terminology used elsewhere ("usage
telemetry" and the distinct ID). Locate the command builder where
.description('Manage anonymous telemetry (enable/disable/status)') is set (in
the setup command) and change the text to something like "Manage usage telemetry
and distinct ID (enable/disable/status)" so the help output matches the updated
UI/UX language.

---

Duplicate comments:
In `@packages/cloud/src/telemetry-headers.ts`:
- Around line 26-29: The function isTelemetryDisabledByEnv currently uses the
nullish coalescing operator so AGENT_RELAY_TELEMETRY_DISABLED='0' can block
DO_NOT_TRACK='true'; update isTelemetryDisabledByEnv to evaluate
AGENT_RELAY_TELEMETRY_DISABLED and DO_NOT_TRACK independently (e.g., check both
values and return true if either equals '1' or case-insensitive 'true'),
referencing the function name isTelemetryDisabledByEnv and the env keys
AGENT_RELAY_TELEMETRY_DISABLED and DO_NOT_TRACK.

---

Nitpick comments:
In `@CHANGELOG.md`:
- Line 35: This changelog entry exposes internal telemetry implementation;
remove or rewrite it to be user-facing and concise: either delete the
`agent-relay` / Relaycast telemetry bullet entirely or replace it with a
one-line, impact-first statement that users care about (e.g., "CLI and SDK
requests are now distinguished in backend telemetry so support can better
diagnose usage") without mentioning internal systems like `agent-relay`,
`Relaycast`, or implementation details about client identity context. Ensure the
final bullet follows the project's rule of one short, user-visible change per
line.
- Line 49: Update the CHANGELOG entry by removing the internal implementation
clause so the bullet reads only that `@agent-relay/sdk` no longer emits
client-side analytics or depends on `@agent-relay/telemetry`; delete the
trailing phrase "SDK/API attribution uses Relaycast origin metadata instead" and
leave the concise, user-facing statement about dependency removal.
- Line 48: The changelog contains an internal build-process detail ("Root builds
now validate the simplified core package set: config, utils, SDK,
harness-driver, harnesses, and CLI.") that must be removed or replaced with a
user-visible impact statement; edit CHANGELOG.md to delete that line (or rewrite
it as a concise, impact-first bullet describing any user-facing change such as
"Simplified core packages to improve install size/stability" if there is an
actual user impact) so the entry only contains user-visible changes and omits
implementation/internal notes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 137b81fa-917c-4405-89f6-c1887670ba3b

📥 Commits

Reviewing files that changed from the base of the PR and between 6e5d793 and 96c78fd.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (26)
  • CHANGELOG.md
  • package.json
  • packages/cli/package.json
  • packages/cli/src/cli/bootstrap.ts
  • packages/cli/src/cli/commands/cloud.test.ts
  • packages/cli/src/cli/commands/cloud.ts
  • packages/cli/src/cli/commands/setup.ts
  • packages/cli/src/cli/entrypoint.test.ts
  • packages/cli/src/cli/lib/broker-lifecycle.ts
  • packages/cli/src/cli/lib/exit.ts
  • packages/cli/src/cli/telemetry/client.ts
  • packages/cli/src/cli/telemetry/config.ts
  • packages/cli/src/cli/telemetry/events.ts
  • packages/cli/src/cli/telemetry/index.ts
  • packages/cli/src/cli/telemetry/machine-id.ts
  • packages/cli/src/cli/telemetry/orchestrator-harness.test.ts
  • packages/cli/src/cli/telemetry/orchestrator-harness.ts
  • packages/cli/src/cli/telemetry/posthog-config.ts
  • packages/cloud/src/auth.test.ts
  • packages/cloud/src/telemetry-headers.ts
  • packages/sdk/src/__tests__/agent-relay.test.ts
  • packages/sdk/src/facade.ts
  • packages/sdk/tsconfig.build.json
  • packages/sdk/tsconfig.json
  • packages/telemetry/package.json
  • packages/telemetry/tsconfig.json
💤 Files with no reviewable changes (4)
  • packages/cli/src/cli/telemetry/orchestrator-harness.test.ts
  • packages/telemetry/tsconfig.json
  • packages/cli/src/cli/telemetry/events.ts
  • packages/cli/src/cli/telemetry/orchestrator-harness.ts
✅ Files skipped from review due to trivial changes (2)
  • packages/cli/src/cli/lib/exit.ts
  • packages/cli/src/cli/commands/cloud.test.ts

@agent-relay-code

Copy link
Copy Markdown
Contributor

⚠️ pr-reviewer did not push — the PR branch advanced during the review, so fixes were withheld to avoid overwriting newer commits. Re-trigger the review once the branch settles. The notes below are advisory and were not pushed.

Reviewed PR #1033 and fixed a regression in CLI telemetry initialization: the first-run notice is now shown and recorded before telemetry capture no-ops for missing PostHog config. Added coverage in client.test.ts. The code change is in client.ts.

Validated:

  • npm run typecheck
  • npm test passed: 833 passed, 5 skipped
  • npm --prefix packages/sdk run test
  • Focused PR tests for cloud auth/workflows, CLI telemetry, entrypoint, and cloud commands

Rust tests were not runnable locally because no Rust toolchain is installed; npm test also skipped the broker build for the same reason.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 28 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/cli/src/cli/telemetry/config.ts">

<violation number="1" location="packages/cli/src/cli/telemetry/config.ts:33">
P2: Distinct ID migration accepts empty-string IDs, so invalid persisted IDs are no longer regenerated.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic


return {
const prefs = JSON.parse(content) as StoredTelemetryPrefs;
const distinctId = prefs.distinctId ?? prefs.anonymousId ?? createDistinctId();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Distinct ID migration accepts empty-string IDs, so invalid persisted IDs are no longer regenerated.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/cli/telemetry/config.ts, line 33:

<comment>Distinct ID migration accepts empty-string IDs, so invalid persisted IDs are no longer regenerated.</comment>

<file context>
@@ -27,26 +29,27 @@ export function loadPrefs(): TelemetryPrefs {
-
-      return {
+      const prefs = JSON.parse(content) as StoredTelemetryPrefs;
+      const distinctId = prefs.distinctId ?? prefs.anonymousId ?? createDistinctId();
+      const normalized: TelemetryPrefs = {
         enabled: prefs.enabled ?? true,
</file context>
Suggested change
const distinctId = prefs.distinctId ?? prefs.anonymousId ?? createDistinctId();
const distinctId = prefs.distinctId?.trim() || prefs.anonymousId?.trim() || createDistinctId();

@agent-relay-code

Copy link
Copy Markdown
Contributor

Reviewed PR #1033 against .workforce/pr.diff, changed files, and local callers. I did not find PR breakage requiring code edits.

Verified locally:

  • npm run typecheck
  • npm run build:core
  • Targeted CLI/cloud telemetry tests from repo root
  • npm --prefix packages/sdk test
  • Prettier check for changed JS/TS/JSON/Markdown files
  • npm run build:telemetry

Limitations:

  • Could not run Rust broker tests because cargo/Rust tooling is not installed in this environment.
  • npm --prefix packages/cloud test exits with “No test files found” due this repo’s Vitest include patterns when run from the package cwd; the changed cloud tests passed from the repo root.

@agent-relay-code

Copy link
Copy Markdown
Contributor

⚠️ pr-reviewer did not push — the PR branch advanced during the review, so fixes were withheld to avoid overwriting newer commits. Re-trigger the review once the branch settles. The notes below are advisory and were not pushed.

Reviewed PR #1033 against .workforce/pr.diff, changed files, and local callers. I did not find PR breakage requiring code edits.

Verified locally:

  • npm run typecheck
  • npm run build:core
  • Targeted CLI/cloud telemetry tests from repo root
  • npm --prefix packages/sdk test
  • Prettier check for changed JS/TS/JSON/Markdown files
  • npm run build:telemetry

Limitations:

  • Could not run Rust broker tests because cargo/Rust tooling is not installed in this environment.
  • npm --prefix packages/cloud test exits with “No test files found” due this repo’s Vitest include patterns when run from the package cwd; the changed cloud tests passed from the repo root.

@agent-relay-code

Copy link
Copy Markdown
Contributor

Reviewed PR #1033 and fixed a cloud auth regression in authorizedApiFetch: caller-supplied content-type now wins over the JSON default while auth and telemetry headers are still added. Added regression coverage for the application/gzip upload case.

Local verification:

  • npm run typecheck passed
  • npm run build passed, with Rust broker build skipped because local Cargo is unavailable
  • npm test passed: 59 files passed, 1 skipped; 836 tests passed, 5 skipped

@agent-relay-code

Copy link
Copy Markdown
Contributor

⚠️ pr-reviewer did not push — the PR branch advanced during the review, so fixes were withheld to avoid overwriting newer commits. Re-trigger the review once the branch settles. The notes below are advisory and were not pushed.

Reviewed PR #1033 and fixed a cloud auth regression in authorizedApiFetch: caller-supplied content-type now wins over the JSON default while auth and telemetry headers are still added. Added regression coverage for the application/gzip upload case.

Local verification:

  • npm run typecheck passed
  • npm run build passed, with Rust broker build skipped because local Cargo is unavailable
  • npm test passed: 59 files passed, 1 skipped; 836 tests passed, 5 skipped

@codeant-ai

codeant-ai Bot commented Jun 3, 2026

Copy link
Copy Markdown

CodeAnt AI is running Incremental review

@codeant-ai codeant-ai Bot added size:XL This PR changes 500-999 lines, ignoring generated files and removed size:XL This PR changes 500-999 lines, ignoring generated files labels Jun 3, 2026
@codeant-ai

codeant-ai Bot commented Jun 3, 2026

Copy link
Copy Markdown

CodeAnt AI Incremental review completed.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/cli/src/cli/telemetry/posthog-config.ts (1)

32-32: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Normalize POSTHOG_HOST before applying override

Line 32 currently accepts whitespace-only values (e.g. ' ') as a valid override, which can produce an invalid host and break telemetry initialization. Reuse trimmed parsing here, like key parsing.

Suggested fix
 const HOST = 'https://i.agentrelay.com';
 
 function readKey(name: string): string | null {
   const raw = process.env[name];
   if (!raw) return null;
   const trimmed = raw.trim();
   return trimmed.length > 0 ? trimmed : null;
 }
+
+function readHost(name: string): string | null {
+  const raw = process.env[name];
+  if (!raw) return null;
+  const trimmed = raw.trim();
+  return trimmed.length > 0 ? trimmed : null;
+}
 
 export function getPostHogConfig(): { apiKey: string; host: string } | null {
-  const host = process.env.POSTHOG_HOST || HOST;
+  const host = readHost('POSTHOG_HOST') || HOST;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/cli/telemetry/posthog-config.ts` at line 32, The
POSTHOG_HOST override is currently taken verbatim, allowing whitespace-only
values to become an invalid host; update the logic around the host constant so
you trim and validate process.env.POSTHOG_HOST before using it: compute a
trimmed value of process.env.POSTHOG_HOST (or null/empty check) and only assign
that to the host variable when non-empty, otherwise fall back to the existing
HOST constant (refer to POSTHOG_HOST, the host constant declaration, and HOST).
🧹 Nitpick comments (1)
packages/cli/src/cli/telemetry/posthog-config.test.ts (1)

6-10: ⚡ Quick win

Add a regression test for whitespace POSTHOG_HOST

Current cases don’t cover the whitespace override edge case. Add a test asserting that POSTHOG_HOST=' ' falls back to https://i.agentrelay.com.

Suggested test case
   it('allows POSTHOG_HOST to override the hosted proxy', () => {
     vi.stubEnv('POSTHOG_API_KEY', 'debug-key');
     vi.stubEnv('POSTHOG_HOST', 'https://posthog.example.test');
 
     expect(getPostHogConfig()).toEqual({
       apiKey: 'debug-key',
       host: 'https://posthog.example.test',
     });
   });
+
+  it('falls back to hosted proxy when POSTHOG_HOST is blank/whitespace', () => {
+    vi.stubEnv('POSTHOG_API_KEY', 'debug-key');
+    vi.stubEnv('POSTHOG_HOST', '   ');
+
+    expect(getPostHogConfig()).toEqual({
+      apiKey: 'debug-key',
+      host: 'https://i.agentrelay.com',
+    });
+  });

Also applies to: 25-33

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/cli/telemetry/posthog-config.test.ts` around lines 6 - 10,
Add a regression test in packages/cli/src/cli/telemetry/posthog-config.test.ts
that stubs POSTHOG_HOST to a whitespace string (e.g., vi.stubEnv('POSTHOG_HOST',
'   ')) and asserts that the code under test (the module being tested in this
file) falls back to the default host 'https://i.agentrelay.com'; place the new
test alongside existing cases (after the beforeEach block) and use the same test
helper or function used in other tests in this file to obtain the resolved host
and expect it to equal 'https://i.agentrelay.com'.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/cli/src/cli/telemetry/posthog-config.ts`:
- Line 32: The POSTHOG_HOST override is currently taken verbatim, allowing
whitespace-only values to become an invalid host; update the logic around the
host constant so you trim and validate process.env.POSTHOG_HOST before using it:
compute a trimmed value of process.env.POSTHOG_HOST (or null/empty check) and
only assign that to the host variable when non-empty, otherwise fall back to the
existing HOST constant (refer to POSTHOG_HOST, the host constant declaration,
and HOST).

---

Nitpick comments:
In `@packages/cli/src/cli/telemetry/posthog-config.test.ts`:
- Around line 6-10: Add a regression test in
packages/cli/src/cli/telemetry/posthog-config.test.ts that stubs POSTHOG_HOST to
a whitespace string (e.g., vi.stubEnv('POSTHOG_HOST', '   ')) and asserts that
the code under test (the module being tested in this file) falls back to the
default host 'https://i.agentrelay.com'; place the new test alongside existing
cases (after the beforeEach block) and use the same test helper or function used
in other tests in this file to obtain the resolved host and expect it to equal
'https://i.agentrelay.com'.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a78cc1ce-ec1a-4c73-a5c8-1c5861f5d356

📥 Commits

Reviewing files that changed from the base of the PR and between 96c78fd and b3cb37d.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • CHANGELOG.md
  • packages/cli/src/cli/telemetry/posthog-config.test.ts
  • packages/cli/src/cli/telemetry/posthog-config.ts
✅ Files skipped from review due to trivial changes (1)
  • CHANGELOG.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
.github/workflows/package-validation.yml (1)

127-129: ⚡ Quick win

Update comment to reflect non-broker packages in skip list.

The comment explains that broker-* packages are skipped because they ship Rust binaries, but the skip list at line 130 also includes several non-broker packages (build-plans, brand, personas, telemetry) that don't fit this description. Consider updating the comment to clarify that the skip list covers both broker packages and other non-Node package directories.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/package-validation.yml around lines 127 - 129, Update the
explanatory comment above the dist-file check to accurately describe the skip
list: mention that it skips broker-* packages (which ship Rust-built binaries)
as well as other non-Node package directories such as build-plans, brand,
personas, and telemetry; adjust the wording near the existing comment block so
it explicitly states "broker packages and other non-Node package directories
(e.g., build-plans, brand, personas, telemetry) are skipped" to match the skip
list.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/cli/src/cli/telemetry/machine-id.test.ts`:
- Line 36: The test builds a RegExp from os.hostname() without escaping, so
hostnames containing regex metacharacters can break matching; update the test to
escape the hostname before interpolation (e.g., create an escapeRegex helper or
use a safe escape utility) and use the escaped value in the RegExp call used in
the expect assertion (the line creating new
RegExp(`^${os.hostname()}-[a-f0-9]{16}$`) and the similar line at 43), ensuring
the pattern becomes ^<escaped-hostname>-[a-f0-9]{16}$.

---

Nitpick comments:
In @.github/workflows/package-validation.yml:
- Around line 127-129: Update the explanatory comment above the dist-file check
to accurately describe the skip list: mention that it skips broker-* packages
(which ship Rust-built binaries) as well as other non-Node package directories
such as build-plans, brand, personas, and telemetry; adjust the wording near the
existing comment block so it explicitly states "broker packages and other
non-Node package directories (e.g., build-plans, brand, personas, telemetry) are
skipped" to match the skip list.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f5607a85-9ab4-4fd5-968f-c00adf485c66

📥 Commits

Reviewing files that changed from the base of the PR and between b3cb37d and 4422148.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (6)
  • .github/workflows/package-validation.yml
  • CHANGELOG.md
  • crates/broker/src/telemetry.rs
  • packages/cli/package.json
  • packages/cli/src/cli/telemetry/config.test.ts
  • packages/cli/src/cli/telemetry/machine-id.test.ts
✅ Files skipped from review due to trivial changes (1)
  • CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/cli/package.json
  • crates/broker/src/telemetry.rs

it('creates a machine id when none exists', () => {
const machineId = loadMachineId();

expect(machineId).toMatch(new RegExp(`^${os.hostname()}-[a-f0-9]{16}$`));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Escape hostname in regex pattern to prevent matching issues.

When os.hostname() contains regex metacharacters (e.g., dots, brackets), the unescaped interpolation can cause incorrect pattern matching or test failures. Although this is test code and the risk is low, escaping ensures correctness across different environments.

🛡️ Proposed fix to escape hostname in regex patterns
-    expect(machineId).toMatch(new RegExp(`^${os.hostname()}-[a-f0-9]{16}$`));
+    expect(machineId).toMatch(new RegExp(`^${os.hostname().replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}-[a-f0-9]{16}$`));

And for line 43:

-    expect(loadMachineId()).toMatch(new RegExp(`^${os.hostname()}-[a-z0-9]+$`));
+    expect(loadMachineId()).toMatch(new RegExp(`^${os.hostname().replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}-[a-z0-9]+$`));

Also applies to: 43-43

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/cli/telemetry/machine-id.test.ts` at line 36, The test
builds a RegExp from os.hostname() without escaping, so hostnames containing
regex metacharacters can break matching; update the test to escape the hostname
before interpolation (e.g., create an escapeRegex helper or use a safe escape
utility) and use the escaped value in the RegExp call used in the expect
assertion (the line creating new RegExp(`^${os.hostname()}-[a-f0-9]{16}$`) and
the similar line at 43), ensuring the pattern becomes
^<escaped-hostname>-[a-f0-9]{16}$.

@willwashburn willwashburn merged commit 00a2c43 into main Jun 3, 2026
46 checks passed
@willwashburn willwashburn deleted the telemetry-cli-sdk-cloud branch June 3, 2026 14:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL This PR changes 500-999 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant