openai4s/telemetry/选择加入的匿名遥测。默认关闭:没有记录同意时,这里不会打开任何 socket、不做域名解析、不启动线程。
冻结的决策(docs/v02-decisions.md)是「仅计数与枚举——零自由文本」,强制方式写的是「用白名单……断言出站载荷没有清单外的键」。
键白名单做不到这件事,攻击只有一行:
{"error_type": "ValueError"} # 枚举
{"error_type": "FileNotFoundError: /home/y/unpublished/cohort.csv"}
同一个键。第二条带着研究对象和某个人的家目录,而未发表的研究数据正是本产品要处理的东西。所以这里的白名单是针对值的:每个字段声明取值域,域外的值永远到不了线上。
| 文件 | 用途 |
|---|---|
__init__.py |
再导出 classify_error 与两个净化函数。不 import 任何能发送数据的东西;import 本包必须保持无副作用,因为「默认关闭」在 import 阶段也必须成立。 |
schema.py |
遥测可以说什么的完整声明:五个取值域类(Enum、Count、Bucket、Version、OpaqueId)与字段表。刻意没有 STRING、TEXT、JSON、MAP、LIST 域,因此新增一个可能携带自由文本的字段必须先新增一个域类——那是一份读起来像隐私决策的 diff,而不是表格里又多一行例行公事。classify_error 是把异常转成遥测值的唯一途径,只按成员判定,绝不透传。 |
consent.py |
遥测是否可以运行,以及它以什么身份运行。install id 内含在同意记录里,因此撤销会在一次操作中同时销毁许可与身份——如果分成两行,「撤销」完全可能清掉标志却留下一个稳定标识符,而活得比同意更久的标识符不是匿名,是记性比用户所同意的更长的化名。重新同意会生成新的 id。OPENAI4S_TELEMETRY 只能把遥测关掉:拒绝不需要许可,但 Dockerfile 里的一行不是同意。 |
wire.py |
唯一把记录变成字节的代码。seal() 按声明逐字段构建信封——不从别人组装好的 dict 里原样搬运任何东西——并返回一个 SealedPayload,其构造函数需要一个模块私有哨兵,因此其他文件无法把跳过校验的字节交给传输层。没有内容时返回 None 而不是空信封:发送「我没什么要说的」仍然是一个数据包,仍然告诉监听者这台机器此刻正在运行。 |
sender.py |
整棵树里唯一发送遥测的代码,而它所有值得一提的地方都是拒绝。没有同意就不发——而且这个检查发生在解析域名之前,因为对 log.openai4s.org 的一次 DNS 查询本身就是同意所要授权的那个信号。不跟随重定向(那是第三方在决定研究遥测去哪里),不用明文 HTTP,URL 里不能带凭据,不接受非 seal 产出的载荷。没有能熬过撤销的队列、没有比撤销活得更久的重试、退出时不 flush。唯一的接缝是 transport:它只替换 socket,不替换其上的任何东西——每一道拒绝照常运行——离线测试套件与 benchmark 因此能对着一个哪儿也不去的传输去驱动身份闸门,而不是从外面往本模块 monkey-patch 一个出站原语。 |
emit.py |
程序其余部分唯一要调的入口。它绝不抛异常(遥测的 bug 不能变成失败的 turn)、绝不阻塞(发送在 daemon 线程上,慢的 collector 不给 turn 增加任何耗时)、每次都重新读同意(没有能熬过撤销的缓存「已启用」)。在常见路径——没有同意——它就是一次读设置然后返回。turn_outcome 把 engine 的 stop-reason 词汇映射到已声明的 outcome 枚举,是一个纯的、经测试的函数,而不是在调用点上的猜测。emit_session_start 按会话乘以 install 身份去重,而且只在确认同意之后才记为已见——所以默认关闭、之后才选择加入的会话仍能发出自己的 session_start;会话中途撤销再同意会生成新 id,新的参与期也配得上自己的那一条。 |
gate.py |
传输闸门:一个 worker、一条有界队列、一道撤销屏障。transmitting() 把同意检查与 socket open 圈进同一临界区,consent.revoke 取同一把锁——所以 revoke 返回之后,没有任何请求还能开始。投递是单 worker + 深度 32 的队列;溢出丢最新并计数,因为丢最旧会打乱这条尽力而为的流,而阻塞调用方等于把遥测放上关键路径。撤销同时清空队列:里面的载荷是用已被销毁的身份封的。 |
collector.py |
接收端,一个参考实现——放在这里是为了让线格式有第二个读者,不是为了让本仓库跑一个公网服务。它镜像 openai4s/share/relay.py:标准库 ThreadingHTTPServer、按客户端计的令牌桶、在读取之前就生效的 body 上限、以及一个 Host 白名单(relay 的 DNS-rebinding 历史正是一个天真的抄袭会继承的东西)。它比 relay 多、而 relay 没理由有的一点:它不信任发送方——每个信封都用客户端净化时用的同一张声明重新校验,因此「仅计数与枚举」即便面对一个无视它的客户端也成立。存储按事件计的计数,绝不存逐安装的日志。 |
以下每一条都对着真实代码路径核实过,而且每一条都能轻易骗过一次随意的评审:
type(e).__name__ —— 内核 cell 执行的是 agent 写的代码,所以类名是用户撰写的文本。class Cohort4471NonResponder(Exception) 直接点名了研究对象。SKILL.md frontmatter。error.code —— provider 经常在那里返回整句话,并且照抄请求内容。openai4s.observability.redact 是为凭据校准的,_looks_opaque 刻意豁免以 / 开头的值,并且有测试钉住这一行为。把它对准研究数据,效果恰好相反:绝对路径原样通过,无害的环境名反被打码。一个长得像保护、实际不保护的闸门比没有闸门更糟,所以有测试断言本包不 import 它。