Files
openclaude/docs/free-code-main-local-system-info-removal-report.md
YoVinchen 5af8acb2bb Checkpoint the full local bridge and audit work before telemetry removal
You asked for all local code to be committed before the broader telemetry-removal pass. This commit snapshots the current bridge/session ingress changes together with the local audit documents so the next cleanup can proceed from a stable rollback point.

Constraint: Preserve the exact local worktree state before the telemetry-removal refactor begins
Constraint: Avoid mixing this baseline snapshot with the upcoming telemetry deletions
Rejected: Fold these staged changes into the telemetry-removal commit | Would blur the before/after boundary and make rollback harder
Confidence: medium
Scope-risk: moderate
Reversibility: clean
Directive: Treat this commit as the pre-removal checkpoint when reviewing later telemetry cleanup diffs
Tested: Not run (baseline snapshot commit requested before the next cleanup pass)
Not-tested: Runtime, build, and typecheck for the staged bridge/session changes
2026-04-09 14:09:44 +08:00

15 KiB
Raw Blame History

free-code-main 本地系统信息外发移除实现报告

  • 分析时间: 2026-04-03
  • 对照文档: docs/local-system-info-egress-audit.md
  • 分析对象: /Users/yovinchen/Downloads/free-code-main
  • 对照基线: /Users/yovinchen/project/claude
  • 分析方式: 静态代码审计 + 关键链路比对 + 同名文件差异核查
  • 说明: 本报告只基于源码静态分析,不包含运行时抓包或服务端验证。

结论摘要

结论是: free-code-main 只“部分移除”了审计文档里的本地系统信息外发链路。

更准确地说,它做的是:

  1. 把 telemetry / analytics / OTel 相关外发出口失活了

    • Datadog
    • Anthropic 1P event logging
    • OTel 事件与 metrics/tracing 初始化
    • GrowthBook 远程评估链路也被间接短路
  2. 但没有把“所有本地信息外发”都移除

    • 模型请求里的环境/项目上下文注入仍在
    • Feedback 上传仍在
    • Transcript Share 仍在
    • Remote Control / Bridge 上传 hostname、目录、分支、git remote URL 的链路仍在
    • Trusted Device 注册仍在
    • /insights 的 ant-only 上传逻辑仍在
  3. 移除方式不是“彻底删代码”,而是“保留兼容接口 + 启动链路短路 + sink/no-op stub 化”

    • 这意味着仓库里仍然保留了不少采集/导出代码。
    • 但默认运行时,关键出口函数已经被改成空实现,导致这些链路无法真正发出请求。

因此,如果问题是:

free-code-main 是否已经把 docs/local-system-info-egress-audit.md 中描述的“本地系统信息外发”整体移除?

答案是:

没有整体移除,只移除了其中“遥测/观测”这一类外发;产品主链路里的上下文外发和若干用户触发上传链路仍然存在。

对照矩阵

审计项 free-code-main 状态 结论
F1 模型请求 system prompt / user context 未移除 默认仍会把 cwd、git 状态、CLAUDE.md、日期以及 prompts 里的平台/壳层/OS 版本注入到模型请求
F2 Datadog analytics 已移除 Datadog 初始化与上报函数被 stub 成 no-op
F3 Anthropic 1P event logging 已移除 1P logger 整体改为空实现,启用判断恒为 false
F4 GrowthBook remote eval 实际已失活 依赖 is1PEventLoggingEnabled(),而 1P 已被硬关,默认不会创建 GrowthBook client
F5 Feedback 未移除 用户触发后仍会 POST 到 claude_cli_feedback
F6 Transcript Share 未移除 用户触发后仍会 POST 到 claude_code_shared_session_transcripts
F7 Remote Control / Bridge 未移除 仍会采集并上送 hostname、目录、分支、git remote URL
F8 Trusted Device 未移除 仍会注册 Claude Code on <hostname> · <platform>
F9 OpenTelemetry 已移除 telemetry 初始化与 logOTelEvent() 都被改成 no-op
F10 /insights 内部上传 未移除 ant-only S3 上传逻辑仍保留

关键判断

这次比对里最重要的判断有两个:

  1. README.md 里的 “Telemetry removed” 只覆盖了“遥测/观测”语义,不等于“所有本地信息外发已删除”。
  2. free-code-main 的移除策略主要是“切断出口”,而不是“删除所有采集代码”。

这也是为什么你会看到:

  • src/services/analytics/metadata.ts 这类环境信息构造代码还在
  • src/utils/api.ts 里上下文统计代码还在
  • src/services/analytics/firstPartyEventLoggingExporter.tssrc/utils/telemetry/bigqueryExporter.ts 这类导出器文件也还在

但是:

  • 事件 sink
  • telemetry bootstrap
  • OTel event logging
  • Datadog / 1P logger 初始化

都已经被改成空实现或被前置条件短路掉了。

已移除部分: 实现方式分析

1. Analytics 公共入口被改成 compatibility boundary + no-op

/Users/yovinchen/Downloads/free-code-main/src/services/analytics/index.ts:4-40 明确写到:

  • “open build intentionally ships without product telemetry”
  • 保留模块只是为了不改动现有调用点
  • attachAnalyticsSink()logEvent()logEventAsync() 都是空实现

这意味着:

  • 各业务模块里仍然可以继续 import { logEvent }
  • 但这些调用不会再入队、不会再挂 sink、也不会再向任何后端发送

对照 /Users/yovinchen/project/claude/src/services/analytics/index.ts,当前工作区版本还保留:

  • 事件队列
  • attachAnalyticsSink() 的真实绑定
  • logEvent() / logEventAsync() 的真实分发

所以这里是非常明确的“出口 stub 化”。

2. Datadog 被直接 stub 掉

/Users/yovinchen/Downloads/free-code-main/src/services/analytics/datadog.ts:1-12 中:

  • initializeDatadog() 直接返回 false
  • shutdownDatadog() 空实现
  • trackDatadogEvent() 空实现

而对照 /Users/yovinchen/project/claude/src/services/analytics/datadog.ts:12-140,基线版本仍然保留:

  • Datadog endpoint
  • 批量缓冲
  • axios.post(...)

因此 F2 可以判定为已移除

3. 1P event logging 被整体空实现

/Users/yovinchen/Downloads/free-code-main/src/services/analytics/firstPartyEventLogger.ts:1-48 中:

  • is1PEventLoggingEnabled() 恒为 false
  • logEventTo1P() 空实现
  • initialize1PEventLogging() 空实现
  • reinitialize1PEventLoggingIfConfigChanged() 空实现

这和基线 /Users/yovinchen/project/claude/src/services/analytics/firstPartyEventLogger.ts:141-220 中真实存在的:

  • getEventMetadata(...)
  • getCoreUserData(true)
  • OTel logger emit

形成了直接对照。

需要注意的是:

  • src/services/analytics/firstPartyEventLoggingExporter.ts 文件仍然存在
  • 里面仍保留 /api/event_logging/batch 的完整实现

但由于 logger 初始化入口已经空了,这个 exporter 在默认路径上已经不会被接上。

因此 F3 的移除方式属于:

保留 exporter 源码,但把“上游 logger/provider 初始化”整体切断。

4. Analytics sink 初始化被清空,启动调用点保留

/Users/yovinchen/Downloads/free-code-main/src/services/analytics/sink.ts:1-10 中:

  • initializeAnalyticsGates() 空实现
  • initializeAnalyticsSink() 空实现

但启动链路并没有删调用点:

  • /Users/yovinchen/Downloads/free-code-main/src/main.tsx:83-86,416-417 仍然 import 并调用 initializeAnalyticsGates()
  • /Users/yovinchen/Downloads/free-code-main/src/setup.ts:371 仍然调用 initSinks()

这说明作者的思路不是“到处改业务调用点”,而是:

保留启动顺序与依赖图,统一在 sink 层面把行为变空。

5. OTel 初始化被显式短路

/Users/yovinchen/Downloads/free-code-main/src/entrypoints/init.ts:207-212 直接把:

  • initializeTelemetryAfterTrust()

改成了立即 return

同时:

  • /Users/yovinchen/Downloads/free-code-main/src/utils/telemetry/instrumentation.ts:1-24
    • bootstrapTelemetry() 空实现
    • isTelemetryEnabled() 恒为 false
    • initializeTelemetry() 返回 null
    • flushTelemetry() 空实现
  • /Users/yovinchen/Downloads/free-code-main/src/utils/telemetry/events.ts:1-12
    • logOTelEvent() 空实现
    • 用户 prompt 内容默认只会被 redactIfDisabled() 处理成 <REDACTED>

而调用点仍保留:

  • /Users/yovinchen/Downloads/free-code-main/src/main.tsx:2595-2597 仍会调用 initializeTelemetryAfterTrust()
  • 多个业务模块仍会调用 logOTelEvent(...)

所以 F9 的移除方式也是:

不删调用点,只把 telemetry bootstrap 和 event emit 统一改成 no-op。

6. GrowthBook 不是“彻底删文件”,而是被前置条件短路

/Users/yovinchen/Downloads/free-code-main/src/services/analytics/growthbook.ts:420-425:

  • isGrowthBookEnabled() 直接返回 is1PEventLoggingEnabled()

而 1P 在 firstPartyEventLogger.ts:26-27 中已经被硬编码为 false

继续往下看:

  • growthbook.ts:490-493 在 client 创建前就会因为 !isGrowthBookEnabled() 返回 null
  • growthbook.ts:685-691748-750 会在取 feature value 时直接返回默认值

这意味着从当前源码推断:

  • 默认路径不会创建 GrowthBook client
  • 默认路径不会执行 remote eval 网络请求
  • 默认路径不会把 deviceID/sessionId/platform/org/email 发出去

所以 F4 应该判定为:

远程评估外发链路实际上已失活。

这里有一个值得单独记录的点:

  • README.md:58-64 写的是 “GrowthBook feature flag evaluation still works locally but does not report back”
  • 但从当前代码看,更准确的说法应该是:
    • 默认的远程评估链路已经被短路
    • 留下的是兼容性结构和本地 override/cache 框架

这条判断是基于源码的推断

7. 本地采集代码仍有残留,但最终不会出网

这部分很关键,容易误判。

free-code-main 不是把所有采集逻辑都删掉了。典型例子:

  • /Users/yovinchen/Downloads/free-code-main/src/services/analytics/metadata.ts:574-740
    • 仍会构造 platformarchnodeVersionterminal、Linux distro、process.memoryUsage()process.cpuUsage()、repo remote hash 等元数据
  • /Users/yovinchen/Downloads/free-code-main/src/utils/api.ts:479-562
    • 仍会收集 gitStatusSizeclaudeMdSize、项目文件数、MCP tool 数量
    • 最后仍调用 logEvent('tengu_context_size', ...)
  • /Users/yovinchen/Downloads/free-code-main/src/main.tsx:2521-2522
    • 启动时仍会执行 logContextMetrics(...)

但由于 src/services/analytics/index.ts:28-38logEvent() 已经是空实现,这些数据虽然可能仍在本地被计算,但不会从该链路继续发出。

所以更准确的评价是:

移除的是 egress不是所有 collection 语句。

未移除部分: 逐项核对

F1. 默认模型请求上下文外发未移除

这部分在 free-code-main 里仍然存在,而且关键文件与基线高度一致。

直接证据:

  • /Users/yovinchen/Downloads/free-code-main/src/constants/prompts.ts:606-648
    • computeEnvInfo() 仍拼接:
      • Working directory
      • Is directory a git repo
      • Platform
      • Shell
      • OS Version
  • /Users/yovinchen/Downloads/free-code-main/src/constants/prompts.ts:651-709
    • computeSimpleEnvInfo() 仍拼接:
      • Primary working directory
      • Platform
      • Shell
      • OS Version
  • /Users/yovinchen/Downloads/free-code-main/src/context.ts:36-109
    • getGitStatus() 仍读取:
      • 当前分支
      • 默认分支
      • git status --short
      • 最近 5 条提交
      • git config user.name
  • /Users/yovinchen/Downloads/free-code-main/src/context.ts:116-149
    • getSystemContext() 仍把 gitStatus 放入上下文
  • /Users/yovinchen/Downloads/free-code-main/src/context.ts:155-187
    • getUserContext() 仍把 CLAUDE.md 内容和日期放入上下文
  • /Users/yovinchen/Downloads/free-code-main/src/utils/api.ts:437-474
    • appendSystemContext() / prependUserContext() 仍会把这些内容拼进消息
  • /Users/yovinchen/Downloads/free-code-main/src/query.ts:449-451,659-661
    • 查询时仍将这些上下文交给模型调用
  • /Users/yovinchen/Downloads/free-code-main/src/services/api/claude.ts:1822-1832
    • 最终仍通过 anthropic.beta.messages.create(...) 发送

补充比对:

  • src/constants/prompts.ts
  • src/context.ts
  • src/utils/api.ts
  • src/query.ts

与基线仓库对应文件比对时,未看到针对这条链路的“移除性改造”。

因此 F1 在 free-code-main没有被移除

F5. Feedback 上传未移除

/Users/yovinchen/Downloads/free-code-main/src/components/Feedback.tsx:523-550 仍会在用户触发时:

  • 刷新 OAuth
  • 取 auth headers
  • POST 到 https://api.anthropic.com/api/claude_cli_feedback

这个文件与基线对应文件比对无差异。

因此 F5 未移除

F6. Transcript Share 上传未移除

/Users/yovinchen/Downloads/free-code-main/src/components/FeedbackSurvey/submitTranscriptShare.ts:37-94 仍会收集:

  • platform
  • transcript
  • subagentTranscripts
  • rawTranscriptJsonl

并 POST 到:

  • https://api.anthropic.com/api/claude_code_shared_session_transcripts

这个文件与基线对应文件比对无差异。

因此 F6 未移除

F7. Remote Control / Bridge 未移除

/Users/yovinchen/Downloads/free-code-main/src/bridge/bridgeMain.ts:2340-2435 仍会采集:

  • branch
  • gitRepoUrl
  • machineName = hostname()
  • dir

随后:

  • /Users/yovinchen/Downloads/free-code-main/src/bridge/bridgeApi.ts:142-178

仍会把这些字段 POST 到:

  • /v1/environments/bridge

上传体中明确包含:

  • machine_name
  • directory
  • branch
  • git_repo_url

src/bridge/bridgeApi.ts 与基线对应文件比对无差异。

因此 F7 未移除

F8. Trusted Device 未移除

/Users/yovinchen/Downloads/free-code-main/src/bridge/trustedDevice.ts:142-159 仍会向:

  • ${baseUrl}/api/auth/trusted_devices

提交:

  • display_name: Claude Code on ${hostname()} · ${process.platform}

这条链路虽然会受 isEssentialTrafficOnly() 影响,但代码并未被删除。

src/bridge/trustedDevice.ts 与基线对应文件比对无差异。

因此 F8 未移除

F10. /insights ant-only 上传未移除

/Users/yovinchen/Downloads/free-code-main/src/commands/insights.ts:3075-3098 仍保留:

  • process.env.USER_TYPE === 'ant' 分支
  • 使用 ff cp 上传 HTML report 到 S3

这条链路不是默认外部版路径,但它在源码里仍然存在。

因此 F10 未移除

与基线仓库的“未改动区域”总结

以下文件经对比未看到差异,说明 free-code-main 没有在这些链路上做“移除”改造:

  • src/constants/prompts.ts
  • src/context.ts
  • src/utils/api.ts
  • src/query.ts
  • src/components/Feedback.tsx
  • src/components/FeedbackSurvey/submitTranscriptShare.ts
  • src/bridge/bridgeApi.ts
  • src/bridge/trustedDevice.ts
  • src/commands/insights.ts

这也是为什么报告结论是“部分移除”,而不是“整体移除”。

最终结论

如果把 docs/local-system-info-egress-audit.md 中的链路拆开看,free-code-main 的状态可以总结为:

  1. 遥测类默认外发

    • Datadog: 已移除
    • 1P event logging: 已移除
    • OTel: 已移除
    • GrowthBook remote eval: 默认已失活
  2. 产品主链路或用户触发上传

    • 模型 system/user context 外发: 未移除
    • Feedback: 未移除
    • Transcript Share: 未移除
    • Remote Control / Bridge: 未移除
    • Trusted Device: 未移除
    • /insights ant-only 上传: 未移除

因此,free-code-main 的真实定位更适合表述为:

它移除了“遥测/观测型外发实现”,但没有移除“产品功能本身依赖的本地信息外发”。

如果后续目标是做“彻底版本地信息外发移除”,还需要继续处理至少这些区域:

  • src/constants/prompts.ts
  • src/context.ts
  • src/utils/api.ts
  • src/components/Feedback.tsx
  • src/components/FeedbackSurvey/submitTranscriptShare.ts
  • src/bridge/*
  • src/commands/insights.ts