uproad/ethotrace
GitHub: uproad/ethotrace
一个通过观测 Ruby 测试运行时行为来动态推导方法签名与类型契约的分析工具。
Stars: 0 | Forks: 0
# Ethotrace
**Ethotrace** 是一个面向 Ruby 的动态类型检查与 signature 解析系统。它不依赖于 nominal type (类型名),
而是通过观察测试执行期间的 method 调用,在三个 channel 中记录“行为”、“传播的 exception”
以及“执行环境要求”。其设计思想受到了 Effect-TS 的 `Effect` 模型的启发。
详细设计请参阅 [`docs/ethotrace-design-handoff-v2.md`](docs/ethotrace-design-handoff-v2.md),
作为 gem 之间稳定契约的 JSONL schema 请参阅 [`docs/schema.md`](docs/schema.md)。
## Monorepo 结构
采用在单一 repository 中放置多个 gem 的 monorepo 结构(计划逐步添加):
| gem | 作用 |
|---|---|
| `gems/ethotrace` | core: 观测引擎 + stdlib adapter + JSONL writer + 合并 CLI |
| `gems/ethotrace-rspec` | RSpec 生命周期接入 |
| `gems/ethotrace-minitest` | Minitest 版(计划中) |
| `gems/ethotrace-rails` | Railtie / ActiveSupport::Notifications / Zeitwerk 集成(计划中) |
| `gems/ethotrace-mcp` | 提供观测结果的 MCP server(与观测进程完全隔离) |
| `gems/ethotrace-rbs` | 向 RBS interface 映射(计划中) |
## 实现状态
| 里程碑 | 内容 | 状态 |
|---|---|---|
| M0 | scaffold + schema v1 确定 | ✅ |
| M1 | prepend wrapper + Tracker + CallContext + 可重入 guard + JSONL writer (Success / Error channel) | ✅ |
| M2 | adapter API + stdlib adapter (ENV/Time/Random/IO/Process) + Requirements 归因 + effect span | ✅ |
| M3 | TracePoint 引擎 + 参数 protocol 观测 | ✅ |
| M4 | `ethotrace-rspec`(suite 生命周期接入)+ 合并 CLI (`ethotrace merge`) | ✅ |
| M5 | 自我应用 + 隔离策略 (`NullIsolation` / `BoxIsolation`) + collector/probe 分离 | ✅ |
| M6 | `ethotrace-mcp`(参考自身观测数据的 MCP server) | ✅ |
| M7 | `ethotrace-rails`(Railtie / Notifications / Zeitwerk) | 计划中 |
| M8 | `ethotrace-rbs`(protocol → RBS `interface` 映射) | 计划中 |
core 的使用方法请参阅 [`gems/ethotrace/README.md`](gems/ethotrace/README.md)。
## 使用方法
如果将 `ethotrace-rspec` 集成到测试中,将在 suite 开始/结束时接入观测 session,
并为每个测试 worker 生成 `tmp/ethotrace/.jsonl` 文件。在 `spec_helper.rb` 中:
```
require "ethotrace/rspec"
Ethotrace::RSpec.setup do |config|
config.observe Order # Order 自身のインスタンスメソッド全部
config.observe Tax, methods: %i[rate] # 一部メソッドだけを指定
# config.options[:trace_c_call] = true # C メソッドもプロトコルに含める(高コスト)
end
```
在并行测试 中,每个 worker 会根据 `TEST_ENV_NUMBER` 和 PID
推导出 session ID(例如:`rspec-w2-pid4242`),并分别写入不同的文件中。
## 合并 (`ethotrace merge`)
将多个并行 worker 输出的 JSONL 合并为一个。以 `(owner, name, kind)` 为 key,
对 protocol、exception 和 Requirements 取并集,并将 `samples` 累加(→ [`docs/schema.md`](docs/schema.md) §7)。
```
bundle exec ethotrace merge tmp/ethotrace/*.jsonl -o ethotrace/observations.jsonl
```
由于输出保持每行一条记录的 `method_observation` 格式,因此**支持再次合并**。
如果省略 `-o`,则会将纯 JSONL 输出到标准输出(进度和摘要输出到标准错误)。
合并后的结果可以直接使用 `ethotrace view` 查看。
## MCP server (`ethotrace-mcp`)
将合并后的观测结果作为 **MCP server (stdio / JSON-RPC)** 公开,以便 AI agent
(首要用户是开发 Ethotrace 的 Claude Code 自身)在开发时能够参考每个 method 的规约。
它是与观测进程**完全隔离**的数据消费者,不会启动任何 instrumentation(设计资料 §9 / M6)。
```
# 既定で ethotrace/observations.jsonl を読み、stdio で待ち受ける
bundle exec ethotrace-mcp
bundle exec ethotrace-mcp path/to/observations.jsonl # 読むストアを明示
```
如果将 `.mcp.json.example` 复制为 `.mcp.json`,Claude Code 就会将其注册为 project scope 的
MCP server。公开的 tool:
| tool | 返回内容 |
|---|---|
| `lookup_method` | 1 个 method 的所有规约(protocol、返回值、exception、Requirements) |
| `list_methods` | 观测到的所有 method |
| `pure_methods` | Requirements 为空(R=∅,即有纯粹的嫌疑) |
| `flaky_suspects` | 接触了非确定性 Requirements(`time.read` / `random.read` 等) |
| `requiring` | 接触了特定 effect 词汇(`db.query` / `env.read` 等) |
| `methods_raising` / `exceptions_of` | 可能导致 exception 逃逸的 method / 该 exception 类 |
| `param_protocol` | 观测到的指定参数的 protocol |
返回的规约是 **observed contract(在测试执行路径下的下限)**。关于详细的自观测循环步骤,
请参阅 `CLAUDE.md`。
## 自我应用 和隔离策略
Ethotrace 将 **观测的安装目标** 作为可替换的隔离策略 (`Ethotrace::Isolation`) 提供。
策略仅决定在“哪个空间”运行 probe (prepend hook),而 collector(记录、归因、
JSONL)和 TracePoint 始终放置在 root 侧。
| 策略 | 条件 | 用途 |
|---|---|---|
| `Isolation::Null` | 默认 | 常规分析(probe = collector 同一空间)|
| `Isolation::Box` | Ruby >= 4.0 + `RUBY_BOX=1` | 自我应用及存在大量 monkey patch 的对象 |
`Isolation::Box` 会将 Ethotrace 新加载到子 [`Ruby::Box`](https://docs.ruby-lang.org/en/4.0/Ruby/Box.html)(Ruby 4.0
experimental) 中,将观测对象隔离到与 root 不同的实体中。这就在结构上解决了
“instrumentation 机制本身成为被观测对象”的自指污染问题。观测事件会从 box 内的 probe
传递给 root 的 Collector。此外,记录的活跃路径通过基于名称的 deny-list
(`Wrapper::SELF_DENY_LIST`) 受到双重保护。
```
# 自己適用デモ: Ethotrace で Ethotrace 自身のメソッドを観測する(main box から起動)
RUBY_BOX=1 ruby gems/ethotrace/script/self_hosting.rb
```
Ruby::Box 的验证结果(实体分离、跨界观测、谱系依赖等 E1〜E6)记录在
[`docs/box-semantics.md`](docs/box-semantics.md) 中,设计详情见设计资料 §4.8。
由于 Ruby::Box 是 experimental 且需要从 main box 启动,因此自我应用的验证需使用上述的
独立测试工具(纯 `RUBY_BOX=1 ruby`)进行(在 `RUBY_BOX=1` 下,由于 stdlib autoload 的问题,
bundler/rspec 无法运行)。**目前不提供对 Rails adapter + BoxIsolation 组合使用的支持**。
## 开发
需要 Ruby >= 3.2。
```
bundle install # 依存解決(ルートの Gemfile が全 gem を束ねる)
bundle exec rake # 全 gem の spec + RuboCop
bundle exec rake spec # テストのみ
bundle exec rake rubocop
```
## 许可证
MIT
标签:Ruby, SOC Prime, 代码观测, 动态类型检查, 开发工具, 批量扫描, 时序数据库, 测试工具, 知识库, 签名分析