Skip to content

bug(fork): fork servers send product analytics to upstream's PostHog by default #23

Description

@nohat

Part of #22.

Problem

The papercut loop's premise is that reports, and everything an agent learns from them, stay on my machines. A fork server does not currently honor that for product analytics: it reports to upstream's PostHog project unless told not to, and nothing in the fork tells it not to. Found while auditing the papercut footprint on fork/prod, 2026-10-05.

What the code shows

  • apps/server/src/telemetry/AnalyticsService.ts:31-39: T3CODE_POSTHOG_KEY defaults to a hardcoded upstream project key, T3CODE_POSTHOG_HOST defaults to https://us.i.posthog.com, and T3CODE_TELEMETRY_ENABLED defaults to true.
  • A grep of docs/fork and scripts/fork finds none of those variables set, so the packaged prod server launched by fork-deploy runs with the defaults. Dev servers started from worktrees do too.
  • Clients load no analytics SDK (docs/internals/product-analytics.md), so the server is the only emitter of product events.
  • Mobile: apps/mobile/app.config.ts defaults observability.tracesUrl to Axiom's endpoint with tracesToken null. Believed inert without a token. Not verified.
  • Event properties were not audited; the issue is that the egress exists, not what it carries.

Likely trigger

Not a regression. Upstream's default, never overridden by the fork.

Proposed fixes

  1. fork-deploy writes T3CODE_TELEMETRY_ENABLED=false into the launchd job environment for prod, and its post-swap health probe confirms the running server has it off (read from the job's environment or a server-reported flag; use whichever exists, add nothing to the server if the job environment is enough). A prod server with telemetry on fails the probe.
  2. Same default for the dev stack the fork launches from worktrees (vp run dev reads the same variables), set where the fork already sets dev env, not by editing upstream files.
  3. Verify mobile sends nothing without a token (read the exporter, then observe from the simulator with the token unset). If it does send, set an explicit empty URL in the fork's config.
  4. A test in scripts/fork/fork-deploy-lib.test.ts that the generated job environment contains the opt-out.
  5. One line in docs/fork/maintenance.md: the fork keeps every report, trace, and event on my machines; the only egress is to model providers.

Surfaces

Server and desktop (the desktop bundles the server, so its launch environment too). Web and mobile clients: no analytics SDK; mobile tracing item above. No provider, contract, or connection-mode change.

Related

#22. docs/fork/posture.md ("Private data does not leave the machine without a reason").

Severity: Medium. No known leak of message content, but the premise of the local loop depends on this being off.

Activity

  1. added
    bugSomething isn't working
    on Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions