ralph-flow-pi 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +428 -0
  3. package/dist/cli.d.ts +9 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +56 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/prompts.d.ts +25 -0
  8. package/dist/commands/prompts.d.ts.map +1 -0
  9. package/dist/commands/prompts.js +249 -0
  10. package/dist/commands/prompts.js.map +1 -0
  11. package/dist/commands/tools.d.ts +47 -0
  12. package/dist/commands/tools.d.ts.map +1 -0
  13. package/dist/commands/tools.js +633 -0
  14. package/dist/commands/tools.js.map +1 -0
  15. package/dist/engine/check-bash.d.ts +121 -0
  16. package/dist/engine/check-bash.d.ts.map +1 -0
  17. package/dist/engine/check-bash.js +373 -0
  18. package/dist/engine/check-bash.js.map +1 -0
  19. package/dist/engine/check.d.ts +47 -0
  20. package/dist/engine/check.d.ts.map +1 -0
  21. package/dist/engine/check.js +298 -0
  22. package/dist/engine/check.js.map +1 -0
  23. package/dist/engine/core.d.ts +153 -0
  24. package/dist/engine/core.d.ts.map +1 -0
  25. package/dist/engine/core.js +1984 -0
  26. package/dist/engine/core.js.map +1 -0
  27. package/dist/engine/lock.d.ts +27 -0
  28. package/dist/engine/lock.d.ts.map +1 -0
  29. package/dist/engine/lock.js +121 -0
  30. package/dist/engine/lock.js.map +1 -0
  31. package/dist/engine/runner.d.ts +108 -0
  32. package/dist/engine/runner.d.ts.map +1 -0
  33. package/dist/engine/runner.js +510 -0
  34. package/dist/engine/runner.js.map +1 -0
  35. package/dist/engine/skills.d.ts +53 -0
  36. package/dist/engine/skills.d.ts.map +1 -0
  37. package/dist/engine/skills.js +109 -0
  38. package/dist/engine/skills.js.map +1 -0
  39. package/dist/engine/step-tools.d.ts +22 -0
  40. package/dist/engine/step-tools.d.ts.map +1 -0
  41. package/dist/engine/step-tools.js +45 -0
  42. package/dist/engine/step-tools.js.map +1 -0
  43. package/dist/engine/types.d.ts +136 -0
  44. package/dist/engine/types.d.ts.map +1 -0
  45. package/dist/engine/types.js +20 -0
  46. package/dist/engine/types.js.map +1 -0
  47. package/dist/headless.d.ts +57 -0
  48. package/dist/headless.d.ts.map +1 -0
  49. package/dist/headless.js +318 -0
  50. package/dist/headless.js.map +1 -0
  51. package/dist/pi/adapter.d.ts +135 -0
  52. package/dist/pi/adapter.d.ts.map +1 -0
  53. package/dist/pi/adapter.js +231 -0
  54. package/dist/pi/adapter.js.map +1 -0
  55. package/dist/pi/interactive.d.ts +28 -0
  56. package/dist/pi/interactive.d.ts.map +1 -0
  57. package/dist/pi/interactive.js +58 -0
  58. package/dist/pi/interactive.js.map +1 -0
  59. package/dist/pi/tui.d.ts +12 -0
  60. package/dist/pi/tui.d.ts.map +1 -0
  61. package/dist/pi/tui.js +12 -0
  62. package/dist/pi/tui.js.map +1 -0
  63. package/dist/tui/app.d.ts +25 -0
  64. package/dist/tui/app.d.ts.map +1 -0
  65. package/dist/tui/app.js +47 -0
  66. package/dist/tui/app.js.map +1 -0
  67. package/dist/tui/embed.d.ts +42 -0
  68. package/dist/tui/embed.d.ts.map +1 -0
  69. package/dist/tui/embed.js +38 -0
  70. package/dist/tui/embed.js.map +1 -0
  71. package/dist/tui/extension.d.ts +88 -0
  72. package/dist/tui/extension.d.ts.map +1 -0
  73. package/dist/tui/extension.js +114 -0
  74. package/dist/tui/extension.js.map +1 -0
  75. package/dist/tui/history-editor.d.ts +38 -0
  76. package/dist/tui/history-editor.d.ts.map +1 -0
  77. package/dist/tui/history-editor.js +55 -0
  78. package/dist/tui/history-editor.js.map +1 -0
  79. package/dist/tui/launcher.d.ts +24 -0
  80. package/dist/tui/launcher.d.ts.map +1 -0
  81. package/dist/tui/launcher.js +97 -0
  82. package/dist/tui/launcher.js.map +1 -0
  83. package/dist/tui/render.d.ts +87 -0
  84. package/dist/tui/render.d.ts.map +1 -0
  85. package/dist/tui/render.js +266 -0
  86. package/dist/tui/render.js.map +1 -0
  87. package/dist/tui/run-app.d.ts +49 -0
  88. package/dist/tui/run-app.d.ts.map +1 -0
  89. package/dist/tui/run-app.js +317 -0
  90. package/dist/tui/run-app.js.map +1 -0
  91. package/dist/tui/run-model.d.ts +162 -0
  92. package/dist/tui/run-model.d.ts.map +1 -0
  93. package/dist/tui/run-model.js +280 -0
  94. package/dist/tui/run-model.js.map +1 -0
  95. package/dist/tui/run-view.d.ts +71 -0
  96. package/dist/tui/run-view.d.ts.map +1 -0
  97. package/dist/tui/run-view.js +167 -0
  98. package/dist/tui/run-view.js.map +1 -0
  99. package/dist/tui/welcome-header.d.ts +40 -0
  100. package/dist/tui/welcome-header.d.ts.map +1 -0
  101. package/dist/tui/welcome-header.js +90 -0
  102. package/dist/tui/welcome-header.js.map +1 -0
  103. package/package.json +55 -0
  104. package/skills/c-to-rust-audit/SKILL.md +67 -0
  105. package/skills/c-to-rust-implement/SKILL.md +151 -0
  106. package/skills/c-to-rust-implement/references/c-to-rust-patterns.md +86 -0
  107. package/skills/c-to-rust-implement/references/conditional-compilation.md +47 -0
  108. package/skills/c-to-rust-implement/references/crate-reference.md +15 -0
  109. package/skills/c-to-rust-implement/references/error-strategies.md +80 -0
  110. package/skills/c-to-rust-implement/references/inline-asm.md +37 -0
  111. package/skills/c-to-rust-plan/SKILL.md +166 -0
  112. package/skills/c-to-rust-plan/references/detection-commands.md +66 -0
  113. package/skills/c-to-rust-test-gen/SKILL.md +130 -0
  114. package/skills/c-to-rust-test-gen/references/proptest-patterns.md +81 -0
  115. package/skills/c-to-rust-test-gen/references/test-porting.md +56 -0
  116. package/skills/c-to-rust-validate/SKILL.md +121 -0
  117. package/skills/everything2rust-audit/SKILL.md +69 -0
  118. package/skills/everything2rust-design/SKILL.md +121 -0
  119. package/skills/everything2rust-design/references/domain-playbooks.md +68 -0
  120. package/skills/everything2rust-design/references/paradigm-map.md +99 -0
  121. package/skills/everything2rust-implement/SKILL.md +101 -0
  122. package/skills/everything2rust-spec/SKILL.md +86 -0
  123. package/skills/everything2rust-spec/references/oracle-strategies.md +96 -0
  124. package/skills/everything2rust-survey/SKILL.md +99 -0
  125. package/skills/everything2rust-test-gen/SKILL.md +68 -0
  126. package/skills/everything2rust-test-gen/references/harness-patterns.md +186 -0
  127. package/skills/everything2rust-validate/SKILL.md +85 -0
  128. package/workflows/c-to-rust.yaml +202 -0
  129. package/workflows/everything2rust.yaml +259 -0
  130. package/workflows/loop.yaml +68 -0
  131. package/workflows/spec.yaml +183 -0
@@ -0,0 +1,81 @@
1
+ # Proptest Patterns for C-to-Rust Translation
2
+
3
+ ## Contents
4
+ - Data Transform Functions(roundtrip / determinism / empty)
5
+ - Stateful APIs(state-machine proptest)
6
+
7
+ Property-based test templates for the TDD baseline. Place in `tests/prop_<module>.rs`.
8
+
9
+ ## Data Transform Functions (Codec/Checksum/Serialize)
10
+
11
+ For functions satisfying "arbitrary input → verifiable property":
12
+
13
+ ```rust
14
+ use proptest::prelude::*;
15
+
16
+ proptest! {
17
+ #[test]
18
+ fn prop_roundtrip_consistent(data in prop::collection::vec(any::<u8>(), 0..512)) {
19
+ let mut encoded = vec![0u8; data.len() * 2 + 16];
20
+ let n = codec::encode(&data, &mut encoded).unwrap();
21
+ let mut decoded = vec![0u8; data.len()];
22
+ let m = codec::decode(&encoded[..n], &mut decoded).unwrap();
23
+ assert_eq!(&decoded[..m], &data);
24
+ }
25
+
26
+ #[test]
27
+ fn prop_checksum_deterministic(data in prop::collection::vec(any::<u8>(), 0..1024)) {
28
+ assert_eq!(codec::checksum(&data), codec::checksum(&data));
29
+ }
30
+
31
+ #[test]
32
+ fn prop_empty_input_no_crash() {
33
+ let mut out = vec![0u8; 16];
34
+ assert!(codec::encode(&[], &mut out).is_ok());
35
+ }
36
+ }
37
+ ```
38
+
39
+ ## Stateful APIs (Objects with init/transform/deinit lifecycle)
40
+
41
+ For modules with `difficulty=stateful`, use state-machine proptest:
42
+
43
+ ```rust
44
+ use proptest::prelude::*;
45
+ use proptest::strategy::{Strategy, ValueTree};
46
+
47
+ #[derive(Debug, Clone)]
48
+ enum Op {
49
+ Connect,
50
+ Write(Vec<u8>),
51
+ Read(usize),
52
+ Flush,
53
+ }
54
+
55
+ fn op_strategy() -> impl Strategy<Value = Op> {
56
+ prop_oneof![
57
+ Just(Op::Connect),
58
+ prop::collection::vec(any::<u8>(), 0..256).prop_map(Op::Write),
59
+ (1usize..1024).prop_map(Op::Read),
60
+ Just(Op::Flush),
61
+ ]
62
+ }
63
+
64
+ proptest! {
65
+ #[test]
66
+ fn prop_arbitrary_op_sequence_no_crash_no_leak(ops in prop::collection::vec(op_strategy(), 0..50)) {
67
+ let mut ctx = storage::Ctx::new();
68
+ for op in &ops {
69
+ match op {
70
+ Op::Connect => { let _ = ctx.connect(); }
71
+ Op::Write(data) => { let _ = ctx.write(data); }
72
+ Op::Read(n) => { let _ = ctx.read(*n); }
73
+ Op::Flush => { let _ = ctx.flush(); }
74
+ }
75
+ }
76
+ // ctx drops at end of scope — no panic = pass
77
+ }
78
+ }
79
+ ```
80
+
81
+ State-machine proptest during red phase: only verify no panic/no leak, not specific return values (stubs are `todo!()`). After implementation: add assertions on correct behavior.
@@ -0,0 +1,56 @@
1
+ # C 测试移植参考(c-to-rust-test-gen)
2
+
3
+ ## 目录
4
+
5
+ - 1. 各框架的用例声明与断言宏
6
+ - 2. 断言语义归一表(精度不降级)
7
+ - 3. 非确定性函数的归一化策略
8
+
9
+ ## 1. 各框架的用例声明与断言宏
10
+
11
+ 读 plan.json `test_framework`,把每个 C 测试用例映射成 Rust `#[test]`:
12
+
13
+ | 框架 | 用例声明 | 断言示例 |
14
+ |------|---------|---------|
15
+ | plain | `void test_x(void)` + `assert()` | `assert(...)` |
16
+ | Unity | `void test_x(void)` + `RUN_TEST` | `TEST_ASSERT_EQUAL(a,b)` |
17
+ | CMocka | `static void x(void **state)` | `assert_int_equal(a,b)` |
18
+ | Check | `START_TEST(x)` | `ck_assert_int_eq(a,b)` |
19
+ | CuTest | `void Testx(CuTest *tc)` | `CuAssertIntEquals(tc,a,b)` |
20
+
21
+ 无论来自哪种框架,断言语义都按下表精确归一。
22
+
23
+ ## 2. 断言语义归一表(精度不降级)
24
+
25
+ | C 断言语义 | Rust 断言 |
26
+ |-----------|----------|
27
+ | `ret == 0` / 等值成功 | `assert_eq!(result, Ok(expected))` |
28
+ | `ret == -1` / 失败 | `assert!(result.is_err())` |
29
+ | `ret == SPECIFIC_ERR` | `assert_eq!(result, Err(AppError::SpecificErr))` |
30
+ | `a == b` / `a != b` | `assert_eq!` / `assert_ne!` |
31
+ | `memcmp(a,b,n)==0` | `assert_eq!(&a[..n], &b[..n])` |
32
+ | `ptr != NULL` / `== NULL` | `assert!(x.is_some())` / `is_none()` |
33
+ | `strcmp(a,b)==0` | `assert_eq!(a, b)` |
34
+ | `fabs(a-b) < eps` | `assert!((a-b).abs() < eps)` |
35
+ | `a>=lo && a<=hi` | `assert!(a>=lo && a<=hi)`(范围精确保留) |
36
+ | `cond && "msg"` | `assert!(cond, "msg")` |
37
+ | 循环里多个 assert | **每个独立保留**,禁止用 `assert!(all(...))` 合并 |
38
+
39
+ 文件命名 `tests/oracle_<module>.rs`。
40
+ 错误路径:对每个 error_variant,确认至少一个测试触发它。
41
+
42
+ ## 3. 非确定性函数的归一化策略
43
+
44
+ 对**非确定性输出**做精确断言会假阳。识别并处理(在 plan.json 对应模块 `notes` 记下策略):
45
+
46
+ | 非确定来源 | 现象 | 归一化做法 |
47
+ |-----------|------|-----------|
48
+ | 指针/地址打印 | `%p`、把地址写进输出 | 比对前把地址字段抹成 `0x0` 后再比 |
49
+ | 时间/PID/随机数 | 时间戳、`rand()`、PID | 注入固定种子 / 固定时钟;不可注入则排除该字段,记 notes |
50
+ | 哈希/集合遍历序 | map/set 迭代顺序不定 | 比对前对输出**排序**,或断言"集合相等"而非"序列相等" |
51
+ | 未初始化 padding | struct 写盘带垃圾字节 | 比对前 memset/掩码 padding 区;或只比有效字段 |
52
+ | 浮点末位 | 不同优化下末位差异 | 用 `(a-b).abs() < eps` 容差比对,不逐字节 |
53
+ | 平台相关(字节序/字长) | `size_t`/字节序差异 | 固定到一种表示后再比;条件编译路径分别处理 |
54
+
55
+ 原则:**能消除非确定性就消除(固定种子/时钟);不能就缩小比对面(只比确定字段)**——但要在 notes 里
56
+ 写清"放弃了对哪部分输出的等价断言、为什么",让 verify 阶段能看到这个让步,不被当成 100% 等价。
@@ -0,0 +1,121 @@
1
+ ---
2
+ name: c-to-rust-validate
3
+ description: 独立 QA 视角对 C→Rust 翻译做最终验收。逐 gate 取证,产出 report.md。在 c-to-rust 工作流的 verify 步骤触发。
4
+ ---
5
+
6
+ 以独立 QA 视角验收完成的 Rust 翻译。不信任实现过程,从头验证一切。每个 conclusion 必须有具体命令证据;发现问题立即修复。
7
+
8
+ ## 输入 / 输出
9
+
10
+ > `<产出目录>` = DO 提示词「产出目录」一节给出的路径(形如 `.ralph-flow/artifacts/<任务摘要>-<后缀>/`)。
11
+
12
+ - 输入:Rust 项目路径(output_dir)、`plan.json`、C 项目路径(source_c_dir)、function-contracts.md(如有)
13
+ - 输出:`<产出目录>/report.md`(逐条验收标准附证据)
14
+
15
+ ## 执行流程
16
+
17
+ 逐条验证以下标准,每条都跑实际命令、收集证据。不达标立即修复,不要等到 CHECK 来发现问题。
18
+
19
+ ### 1. 可执行文件
20
+
21
+ ```bash
22
+ cd <output_dir>
23
+ cargo clean && cargo build --release # "Finished",无 error
24
+ cargo run --release -- --help # 不 panic 正常启动
25
+ ```
26
+
27
+ ### 2. 测试框架
28
+
29
+ 检查所有测试使用 Rust 主流测试框架(#[test]、rstest、proptest 等),不依赖外部 C 测试框架或脚本。
30
+
31
+ ```bash
32
+ grep -rn '#\[test\]' tests/ # 确认 Rust 测试注解
33
+ grep -rn 'proptest\|rstest' tests/ # 确认属性测试框架
34
+ ```
35
+
36
+ ### 3. 源码全量翻译
37
+
38
+ ```bash
39
+ cd <output_dir>
40
+ grep -rn 'todo!\|unimplemented!()' src/ tests/ | grep -v '//' # 无输出
41
+ grep -rn 'dbg!' src/ | grep -v '//' # 无输出
42
+ grep -rn '#\[ignore\]' tests/ src/ # 无输出
43
+ ```
44
+
45
+ 手动抽查 src/ 下的函数体,确认没有空函数体或仅返回默认值的占位实现。
46
+
47
+ ### 4. 编译与测试通过
48
+
49
+ ```bash
50
+ cd <output_dir>
51
+ cargo test --all # 全 ok,无 FAILED,无 #[ignore]
52
+ cargo clippy -- -D warnings # 零 warning
53
+ ```
54
+
55
+ ### 5. Unsafe 审计
56
+
57
+ ```bash
58
+ cd <output_dir>
59
+ cargo geiger 2>&1 | tee /tmp/geiger.txt
60
+ # 取本项目 crate 行 Expressions used/total,要求 < 10%
61
+ ```
62
+
63
+ - 每处 `unsafe {` 前一行有 `// SAFETY:` 注释
64
+ - 无巨型 unsafe 块(单块 > 50 行)
65
+
66
+ ### 6. 业务逻辑验证
67
+
68
+ 这是最核心的标准。对照 plan.json 每个模块的 public_functions 和 internal_functions,逐函数验证:
69
+
70
+ - C 原实现与 Rust 实现的语义等价性
71
+ - 错误路径是否完整保留
72
+ - 状态转换是否完整
73
+ - 资源管理是否正确
74
+
75
+ ### 7. 单元测试覆盖
76
+
77
+ 不只看行覆盖率数字,还要检查测试质量:
78
+
79
+ ```bash
80
+ cd <output_dir>
81
+ cargo llvm-cov --summary-only 2>&1
82
+ ```
83
+
84
+ - 每个模块的核心函数有针对性测试(不是间接调用到就算)
85
+ - happy path 和 error path 都有覆盖
86
+ - 边界条件有测试
87
+ - 有 property-based 测试覆盖数据变换
88
+
89
+ ## 生成 report.md
90
+
91
+ 写入 `<产出目录>/report.md`:
92
+
93
+ ```markdown
94
+ # C→Rust 翻译验收报告
95
+
96
+ ## 总体结论:[PASS / FAIL]
97
+
98
+ ## 关键指标
99
+ - 项目:<output_name>_rust
100
+ - Unsafe:cargo geiger Expressions used/total = X/Y ≈ Z%(目标 <10%)
101
+ - 测试:N 通过(oracle N1 + prop N2 + golden N3)
102
+ - 代码规模:C Nc 行 → Rust Nr 行
103
+ - C 函数覆盖:已实现 M / 总计 T
104
+
105
+ ## 验收标准逐条结果
106
+ ### 1. 可执行文件 — [PASS/FAIL]
107
+ ### 2. 测试框架 — [PASS/FAIL]
108
+ ### 3. 源码全量翻译 — [PASS/FAIL]
109
+ ### 4. 编译与测试通过 — [PASS/FAIL]
110
+ ### 5. Unsafe 审计 — [PASS/FAIL]
111
+ ### 6. 业务逻辑验证 — [PASS/FAIL]
112
+ ### 7. 单元测试覆盖 — [PASS/FAIL]
113
+
114
+ ## 保留 Unsafe 的理由(摘录每处 // SAFETY:)
115
+ ## 遗留问题及修复建议
116
+ ```
117
+
118
+ ## 完成标准
119
+
120
+ - 7 条验收标准全部通过
121
+ - report.md 生成,每条附实际命令输出证据
@@ -0,0 +1,69 @@
1
+ ---
2
+ name: everything2rust-audit
3
+ description: 独立审计 everything2rust 重构质量。逐能力对照 behavior-spec.md 验证行为等价:输出、副作用、错误路径、不变量、数据格式互通。发现偏差立即修复。在 everything2rust 工作流的 audit-core 和 audit-full 步骤触发。
4
+ ---
5
+
6
+ 你是审计师,刚接手别人完成的重构。你的任务不是重跑测试(CI 已经跑了)——是找出**测试没抓住的行为偏差**。测试是契约的采样,不是契约本身;审计就是补上采样之外的核对。
7
+
8
+ 判据永远是 behavior-spec.md 的契约,不是代码形状。Rust 实现和源实现结构不同是设计使然,不是问题;给定契约输入产生不同可观察行为才是问题。
9
+
10
+ ## 输入 / 范围
11
+
12
+ > `<产出目录>` = DO 提示词「产出目录」一节给出的路径(形如 `.ralph-flow/artifacts/<任务摘要>-<后缀>/`)。
13
+
14
+ - 输入:`<产出目录>/plan.json` + `behavior-spec.md` + `golden/` + Rust 项目 + 源项目
15
+ - **audit-core**:`phase: core` 增量的能力
16
+ - **audit-full**:全部能力,重点有状态/并发/交互类
17
+
18
+ ## 审计方法(逐能力)
19
+
20
+ 对范围内每个能力走一遍:
21
+
22
+ ### 1. 契约重读
23
+
24
+ 读该能力的契约,列出全部可核对点:输出、副作用、**每条错误路径**、**每个边界**、不变量。错误路径和边界是重构中最常丢的——原实现里那个"文件损坏时不覆盖原文件"的细节,测试可能没采到。
25
+
26
+ ### 2. 实现走查
27
+
28
+ 读 Rust 实现,逐点回答"契约的这一条,代码在哪里保证?"。回答不上来的点标记存疑。同时核对:
29
+
30
+ - 契约之外有没有**多出来的行为**(Rust 实现顺手加的校验、改掉的默认值)——未在 parity_exceptions 里的都算偏差
31
+ - 源实现走查交叉验证:对存疑点回到源代码确认原行为到底是什么(不要凭契约文字想象,契约也可能写错——写错则修契约并留记录)
32
+
33
+ ### 3. 动手取证
34
+
35
+ 存疑点用实验裁决,别停留在读代码:
36
+
37
+ ```bash
38
+ # golden 全跑 + 差分测试(原系统可运行时)
39
+ cargo test 2>&1 | tail -5
40
+ cargo test -- --ignored 2>&1 | tail -20 # 差分测试在这里
41
+
42
+ # 手工差分:把契约的边界输入分别喂给两边
43
+ <原系统 run_cmd> <边界输入> # 亲眼看原行为
44
+ cargo run --release -- <边界输入>
45
+ ```
46
+
47
+ 数据格式类能力加验互通:Rust 写的文件让原系统读、原系统写的让 Rust 读。
48
+
49
+ ### 4. checklist 能力
50
+
51
+ test-map.json 标 checklist 的能力没有自动测试兜底,逐条人工核对 `tests/CHECKLIST.md`:能验证的当场验证(起程序、看输出),当前环境无法验证的(需要显示器/音频)如实标注"未验证+原因",不许标"通过"。
52
+
53
+ ### 5. 发现偏差 → 立即修复
54
+
55
+ 审计发现的每个偏差:先补一个会失败的测试钉住它(防回归),再修实现到测试通过。修复走 implement 的自愈循环。修完在 plan.json 对应能力的 notes 里记一笔(发现了什么、怎么修的)——verify 步骤会参考。
56
+
57
+ ## 反模式(审计失败的常见方式)
58
+
59
+ - **只看测试绿就通过** — 测试是别人写的采样,你的价值在采样之外
60
+ - **拿代码结构当判据** — "没有和源码对应的函数"不是偏差;"错误路径行为变了"才是
61
+ - **对 checklist 项走过场** — 标注"通过"必须有你亲手验证的证据
62
+ - **发现小偏差记下来但不修** — 本步骤职责就是修,留给后面只会更贵
63
+
64
+ ## 完成标准
65
+
66
+ - 范围内每个能力有审计结论:契约逐点核对过、存疑点有实验证据
67
+ - golden 全过;差分测试(可行时)全过;数据格式互通验证过
68
+ - 发现的偏差全部修复且有钉住测试;plan.json notes 有记录
69
+ - 无 parity_exceptions 之外的行为偏差残留
@@ -0,0 +1,121 @@
1
+ ---
2
+ name: everything2rust-design
3
+ description: grill 式方案设计:拷问设计树每个分支(目标形态/架构/子系统选型/迁移顺序/测试策略/unsafe 政策),每个决策查证据、记 ADR。产出 design.md、decisions.md 和机器可读的 plan.json。在 everything2rust 工作流的 design 步骤触发。
4
+ ---
5
+
6
+ 你是架构师。行为契约(behavior-spec.md)定义了"必须保留什么";这一步决定"用什么样的 Rust 系统去承载它"。这不是翻译计划——是一次以行为契约为约束的重新设计。源系统的类继承层次、动态类型技巧、框架惯例都不需要在 Rust 里复刻;需要复刻的只有契约中的可观察行为。
7
+
8
+ 方法是 grill 式的:把设计拆成一棵决策树,逐分支拷问自己,每个问题都像严苛的评审人那样追问到底。**能靠证据回答的绝不拍脑袋**——证据来自源码事实(读代码)、契约要求(读 behavior-spec)、crate 生态现状(查 crates.io/docs.rs、看维护状态和 API 形态)。每个决策落成一条 ADR。
9
+
10
+ ## 输入 / 输出
11
+
12
+ > `<产出目录>` = DO 提示词「产出目录」一节给出的路径(形如 `.ralph-flow/artifacts/<任务摘要>-<后缀>/`)。
13
+
14
+ - 输入:`<产出目录>/behavior-spec.md` + `system-map.md` + `capabilities.md` + 源项目
15
+ - 输出(均写入 `<产出目录>/`):
16
+ - `design.md` — 架构方案(人读)
17
+ - `decisions.md` — ADR 集(评审与追溯用)
18
+ - `plan.json` — 增量计划(机器可读,驱动后续全部步骤)
19
+
20
+ ## 参考资料(先读再设计)
21
+
22
+ - **[references/domain-playbooks.md](references/domain-playbooks.md)** — 按 system-map 判定的领域读对应 playbook:推荐技术栈、架构形态、领域坑
23
+ - **[references/paradigm-map.md](references/paradigm-map.md)** — 源语言范式 → Rust 惯用法映射;设计模块结构和处理"这个动态特性怎么办"时查
24
+
25
+ ## Grill 协议:设计树逐分支拷问
26
+
27
+ 对下面每个分支:**提出问题 → 列出 2-3 个真实可选项 → 查证据 → 下结论 → 记 ADR**。一个分支的结论会约束后续分支(先定形态再定架构,先定架构再选 crate),按序走。
28
+
29
+ ```
30
+ 设计树:
31
+ 1. 目标形态 — bin / lib / workspace?CLI 还是守护进程?保持原接口还是借机调整?
32
+ 2. 总体架构 — 分层?六边形?ECS?流水线?模块如何划分?(不必沿用源系统的划分)
33
+ 3. 子系统选型 — 对 system-map 依赖清单中每个架构级依赖:Rust 生态用什么替代?
34
+ (web 框架、游戏引擎、GUI 框架、序列化、数据库、异步运行时……)
35
+ 4. 范式落差处理 — 源系统重度使用的动态特性/继承/GC 模式,映射方案是什么?(查 paradigm-map)
36
+ 5. 迁移顺序 — 增量如何切分?walking-skeleton 包含什么?哪些能力先做(高风险先行)?
37
+ 6. 测试策略 — golden harness 怎么搭?differential 是否可行?checklist 项何时人工核对?
38
+ 7. 性能与资源 — 契约中有性能要求吗?并发模型选什么?
39
+ 8. unsafe 政策 — 预算多少(默认 <10%)?哪些位置预期需要 unsafe(FFI/SIMD)?
40
+ 9. 范围取舍 — 有没有行为该故意不保留?(废弃功能、原系统 bug、平台特定行为)
41
+ → 每一条进 parity_exceptions,必须有 ADR
42
+ ```
43
+
44
+ 每个分支的拷问标准:如果一个评审人问"为什么不用 X?"、"这个选择在什么情况下会被证明是错的?",你的 ADR 里要已经有答案。回答不了就去查——读源码、查 crate 文档、跑个小实验。
45
+
46
+ ## 产出格式
47
+
48
+ ### decisions.md — ADR 集
49
+
50
+ ```markdown
51
+ ## ADR-3: 渲染子系统用 macroquad 而非 bevy
52
+ - **问题**:原游戏用 canvas 2d 即时渲染,约 30 个 draw call/帧,无复杂场景图。Rust 侧渲染栈选什么?
53
+ - **选项**:bevy(全家桶 ECS)/ macroquad(轻量即时模式)/ 手写 wgpu
54
+ - **证据**:源码 src/render.ts 仅 400 行、纯 2d 图元;契约 cap-render 是 checklist 项无精确像素要求;bevy 引入 ECS 会迫使全部游戏逻辑重构进 ECS 范式,与"模拟核心已按纯函数设计"(ADR-2)冲突
55
+ - **选择**:macroquad
56
+ - **推翻条件**:若后续发现需要复杂场景图/骨骼动画/shader 管线,升级到 bevy 并重评 ADR-2
57
+ ```
58
+
59
+ 关键分支(形态、架构、每个子系统、迁移顺序、测试策略、unsafe 政策)每个至少一条 ADR。理由必须引用证据,"业界流行"不是理由。
60
+
61
+ ### design.md — 架构方案
62
+
63
+ 模块划分与职责、数据流、核心类型与 trait 草图(签名级即可)、错误处理策略、与契约的映射(每个模块承载哪些能力)。覆盖全部能力,同时警惕过度设计:契约不要求的扩展点、抽象层,一个都不加。
64
+
65
+ ### plan.json — 增量计划
66
+
67
+ ```json
68
+ {
69
+ "source": {
70
+ "dir": "/abs/source", "languages": ["typescript"], "domain": "game",
71
+ "build_cmd": "npm run build", "test_cmd": "npm test", "run_cmd": "npm start", "runnable": true
72
+ },
73
+ "target": {
74
+ "output_name": "<project>_rust",
75
+ "output_dir": "<工作区内绝对路径>/<project>_rust",
76
+ "crate_kind": "bin",
77
+ "rust_edition": "2021",
78
+ "smoke_cmd": "cargo run --release -- --version",
79
+ "unsafe_budget_pct": 10
80
+ },
81
+ "stack": [
82
+ { "subsystem": "rendering", "source_tech": "canvas 2d", "rust_choice": "macroquad", "adr": "ADR-3" },
83
+ { "subsystem": "serialization", "source_tech": "JSON.stringify", "rust_choice": "serde + serde_json", "adr": "ADR-4" }
84
+ ],
85
+ "capabilities": [
86
+ { "id": "cap-save-load", "increment": "inc-2", "oracle": "golden", "status": "pending" }
87
+ ],
88
+ "increments": [
89
+ {
90
+ "id": "inc-1", "name": "walking-skeleton", "phase": "core",
91
+ "capabilities": ["cap-startup", "cap-config"],
92
+ "exit_criteria": "smoke_cmd 端到端可运行;inc-1 能力测试全绿"
93
+ },
94
+ {
95
+ "id": "inc-2", "name": "core-domain", "phase": "core",
96
+ "capabilities": ["cap-game-state", "cap-save-load"],
97
+ "exit_criteria": "核心域测试全绿,含 golden 全过"
98
+ }
99
+ ],
100
+ "parity_exceptions": [
101
+ { "behavior": "原系统崩溃于超长玩家名(已知 bug)", "replacement": "返回 ValidationError", "adr": "ADR-9" }
102
+ ]
103
+ }
104
+ ```
105
+
106
+ 字段约束:
107
+ - 每个能力恰好属于一个 increment;`increments[0]` 必须是 walking-skeleton——**先让系统端到端跑起来**(哪怕只有启动+一个最小能力),骨架通了才知道选型能不能落地
108
+ - phase ∈ {core, full}:core = walking-skeleton + 核心域(系统的存在理由),full = 其余
109
+ - 增量排序原则:高风险/高不确定选型早验证(渲染栈、异步运行时这类"选错要翻工"的放前面);依赖别人的能力排后
110
+ - `parity_exceptions` 是全工作流唯一允许行为偏离的白名单,spec 步骤标注的"原系统 bug"候选在这里裁决
111
+ - `smoke_cmd` 与领域匹配:服务类用"启动+健康检查+关停",游戏/GUI 类允许 `--version` 级(真运行留给 checklist)
112
+ - 所有路径绝对路径;output_dir 在工作区内
113
+
114
+ ## 完成标准
115
+
116
+ - decisions.md 覆盖设计树全部关键分支,每条 ADR 有证据引用和推翻条件
117
+ - design.md 覆盖全部能力、无契约不要求的抽象
118
+ - plan.json 合法且满足上述字段约束
119
+ - 三个文件写入 `<产出目录>/`
120
+
121
+ (本步骤是手动步骤:CHECK 通过后工作流会暂停,供用户审查选型与架构后再继续。)
@@ -0,0 +1,68 @@
1
+ # 领域 Playbook——按 system-map 的 domain 读对应一节
2
+
3
+ ## 目录
4
+ - CLI 工具
5
+ - 库 / SDK
6
+ - Web 服务
7
+ - 游戏
8
+ - GUI 应用
9
+ - 数据管道 / 科学计算
10
+ - 系统工具 / 底层
11
+
12
+ 每节给出:默认技术栈(有充分理由才偏离)、架构形态、测试策略要点、领域坑。crate 选择原则统一:优先 std;引 crate 前查维护状态(最近发布时间、下载量、开 issue 情况);同类只选一个。
13
+
14
+ ## CLI 工具
15
+
16
+ - **栈**:clap(derive 风格)+ anyhow(bin 层错误)+ thiserror(lib 层错误);彩色输出 owo-colors;进度条 indicatif(原系统有才加)
17
+ - **架构**:薄 `main.rs`(参数解析+错误呈现)+ `lib.rs`(全部逻辑)。逻辑放 lib 是测试策略的前提——单元测试测 lib,assert_cmd 测二进制
18
+ - **测试**:golden 语料直接用 assert_cmd 重放(args/stdin → stdout/stderr/exit code);退出码和 stderr 格式是契约的一部分
19
+ - **坑**:原系统的 shell 交互细节(管道行为、TTY 检测、信号处理、locale)容易漏;stdout 与 stderr 的用途划分必须与原系统一致(下游脚本可能在解析)
20
+
21
+ ## 库 / SDK
22
+
23
+ - **栈**:thiserror;serde(数据类型可序列化时);feature flags 控制可选依赖
24
+ - **架构**:公开 API 是设计核心——对照 behavior-spec 设计 pub 接口,内部结构自由。API 设计遵循 Rust API Guidelines(命名、Builder、类型状态)
25
+ - **测试**:golden 语料(driver 脚本采的输入输出对)→ 集成测试;round-trip/不变量 → proptest;文档示例写成 doctest
26
+ - **坑**:源语言的异常层次要映射为有意义的 Err 枚举(不是一个大 `Error(String)`);源 API 的"接受一切"(动态参数、可选字段大对象)要拆成类型安全的入口,接口形态变化记入 design.md 的 API 映射表
27
+
28
+ ## Web 服务
29
+
30
+ - **栈**:axum + tokio + serde + tower(中间件);数据库 sqlx(编译期检查 SQL);需要 ORM 语义再考虑 sea-orm;HTTP 客户端 reqwest;可观测 tracing
31
+ - **架构**:handler(薄)→ service(业务)→ repository(存储);或按契约直接组织为"每能力一模块"。路由表集中声明,与 behavior-spec 的接口清单一一对应
32
+ - **测试**:golden 的请求→响应对用 axum 的 `tower::ServiceExt::oneshot` 或起真实端口重放;外部依赖用 wiremock;数据库测试用 testcontainers 或事务回滚
33
+ - **坑**:REST 契约兼容是硬要求——status code、错误 body 格式、分页参数名都不能变(客户端在依赖);认证/session 语义(过期、刷新)容易走样;中间件顺序影响可观察行为(CORS、压缩)
34
+
35
+ ## 游戏
36
+
37
+ - **栈**(按复杂度选):
38
+ - 2d 轻量(图元/精灵,无复杂场景图)→ **macroquad**(即时模式,几乎零样板)
39
+ - 需要 ECS/场景/资产管线/3d → **bevy**(全家桶,但迫使逻辑进 ECS 范式——确认这个约束可接受再选)
40
+ - 介于两者 → ggez(2d 框架)
41
+ - 数学统一 glam;确定性随机 rand + 固定 seed;序列化 serde + bincode/RON
42
+ - **架构**:**模拟与呈现分离**是最重要的一刀——`sim` 模块(纯逻辑:状态+输入→新状态,无渲染依赖、无真实时钟、注入 RNG)+ `present` 模块(渲染/音频/输入采集)。固定 timestep 更新模拟,渲染插值。这个分离直接决定了游戏逻辑可测试
43
+ - **测试**:sim 模块吃 golden 的"输入序列→状态快照"语料;round-trip 测存档;proptest 测守恒不变量(物品总数、血量上下界);present 层 checklist 人工核对
44
+ - **坑**:原游戏逻辑常和渲染耦合(update 里直接 draw)——剥离是设计工作而非翻译工作,在 design.md 里明确切割线;浮点物理跨平台不确定,golden 比对用容差或定点数;帧率依赖的逻辑(按帧计数的 buff)改固定 timestep 后行为会漂移,逐个核对
45
+
46
+ ## GUI 应用
47
+
48
+ - **栈**(按取舍选):
49
+ - 逻辑复杂、UI 朴素 → **egui**(即时模式,最快落地)
50
+ - 要系统原生感/成熟组件 → **iced**(Elm 架构)或 slint
51
+ - 原系统是 web 技术栈且前端想保留 → **tauri**(Rust 后端 + 原前端资产)——前端不用重写,重构聚焦后端逻辑
52
+ - **架构**:文档模型/编辑操作/撤销栈/文件 IO 全部进 `core` 模块(无 UI 依赖),UI 层只做绑定。撤销栈用命令模式(操作对象化)
53
+ - **测试**:core 按"库"策略全覆盖;文件格式互通(旧文件必须能打开)是硬契约;UI checklist
54
+ - **坑**:原框架的数据绑定魔法(观察者、双向绑定)在 Rust 里显式化——消息/事件枚举比回调网络更惯用;剪贴板/拖放/IME 等平台行为按 checklist 处理
55
+
56
+ ## 数据管道 / 科学计算
57
+
58
+ - **栈**:polars(DataFrame)/ ndarray(数值张量)+ rayon(数据并行);Arrow 生态 arrow-rs;CSV/Parquet 用 polars 自带
59
+ - **架构**:按流水线阶段组织模块(ingest → transform → output),每阶段输入输出类型显式
60
+ - **测试**:golden 的"输入数据集→输出数据集"比对(浮点列容差);性质测试(行数守恒、schema 稳定)
61
+ - **坑**:数值精度——源系统(尤其 Python/JS)的浮点累积顺序不同会导致尾数差异,契约容差要提前定;NaN/null 语义各家不同(pandas 的 NaN vs polars 的 null),逐列核对
62
+
63
+ ## 系统工具 / 底层
64
+
65
+ - **栈**:nix/rustix(Unix 系统调用);libc 仅 FFI 边界;异步 IO 看形态(网络多 → tokio;纯文件/进程 → std 线程足够)
66
+ - **架构**:平台相关代码集中到 `platform` 模块 + cfg 门控;其余保持平台无关
67
+ - **测试**:golden 重放(注意沙箱路径归一化);系统调用重的逻辑抽 trait 便于测试替身
68
+ - **坑**:这是 unsafe 预算的主要消耗方——mmap/ioctl/信号处理集中封装,每处 SAFETY 注释;权限/root 行为、信号语义按 checklist 或集成环境验证
@@ -0,0 +1,99 @@
1
+ # 范式映射——源语言构造 → Rust 惯用法
2
+
3
+ 设计模块结构、以及实现中遇到"这个特性 Rust 怎么表达"时查本表。原则:**映射语义,不映射语法**。源系统用继承不代表 Rust 要 trait 对象——先问"这个继承在表达什么"(多态分发?代码复用?开闭扩展点?),再选对应工具。
4
+
5
+ ## 目录
6
+ - 类型系统落差
7
+ - 面向对象构造
8
+ - 内存与资源管理
9
+ - 错误处理
10
+ - 并发模型
11
+ - 函数式 / 动态特性
12
+ - 全局状态与生命周期
13
+ - 各源语言速查
14
+
15
+ ## 类型系统落差
16
+
17
+ | 源构造 | Rust 映射 | 备注 |
18
+ |--------|-----------|------|
19
+ | 动态类型值(任意 JSON/dict) | 边界处 `serde_json::Value`,内部尽早转强类型 struct | "解析后不再是动态的"——动态性止步于 IO 边界 |
20
+ | null / undefined / None | `Option<T>` | 源系统区分 null 与 undefined 时,确认契约是否依赖该区分(多半不该依赖) |
21
+ | 鸭子类型("有 .read() 就行") | trait | 只为真实存在的多个实现建 trait;单实现直接用具体类型 |
22
+ | 字符串(各语言语义不同) | `String`/`&str`(UTF-8) | JS 的 UTF-16 索引、Python 的码点索引与 Rust 字节索引不同——凡契约涉及"第 n 个字符/长度",逐处核对 |
23
+ | 大整数默认(Python int) | i64/u64 或 num-bigint | 看源码实际值域,契约有溢出行为时显式处理 |
24
+ | 隐式数值转换 | `as`/`From`/`TryFrom` 显式化 | JS 的 `==` 弱比较、Python 的 int/float 混算——语义等价靠测试兜底 |
25
+
26
+ ## 面向对象构造
27
+
28
+ | 源构造 | Rust 映射 | 选择标准 |
29
+ |--------|-----------|---------|
30
+ | 继承(多态分发) | 封闭集合 → `enum` + match;开放集合 → `Box<dyn Trait>` | 变体集合编译期已知选 enum(穷尽检查是白拿的);插件式扩展点才用 trait 对象 |
31
+ | 继承(代码复用) | 组合 + 委托;共享逻辑抽成函数或默认 trait 方法 | 不要为复用建 trait 层次 |
32
+ | 抽象类/接口 | trait(可带默认方法) | |
33
+ | 方法重载 | 不同名函数,或泛型 + `impl Into<T>` | Rust 无重载,命名区分更清晰 |
34
+ | 运算符重载 | `std::ops` trait | 仅当源语义确实是代数运算 |
35
+ | 静态方法/类方法 | 关联函数 | |
36
+ | getter/setter 网络 | 公开字段或按需方法 | 无逻辑的 setter 直接暴露字段 |
37
+ | 访问者模式 | match + enum | 访问者多半是"缺 match 的语言"的补丁 |
38
+
39
+ ## 内存与资源管理
40
+
41
+ | 源构造 | Rust 映射 | 备注 |
42
+ |--------|-----------|------|
43
+ | GC 对象图(树状) | 所有权 + `Box` | 大多数"共享"其实是树,先试单所有者 |
44
+ | GC 对象图(真共享) | `Rc<RefCell<T>>`(单线程)/ `Arc<Mutex<T>>`(跨线程) | 先质疑:是否可改为 id 引用 |
45
+ | 循环引用(双向链接、父子互指) | 索引/id + 中心存储(`Vec`/slotmap/generational-arena) | 游戏实体、图结构的标准解法;比 `Weak` 网络好维护 |
46
+ | 析构/finalizer/with 语句/defer | `Drop` + RAII | 源系统 finalizer 时机不确定,Rust Drop 确定——时机差异一般是改进,契约有依赖再核对 |
47
+ | 手动 close()/dispose() | `Drop` 为主;需要错误处理的关闭再加显式 `close(self) -> Result` | |
48
+
49
+ ## 错误处理
50
+
51
+ | 源构造 | Rust 映射 | 备注 |
52
+ |--------|-----------|------|
53
+ | 异常(业务可恢复) | `Result<T, E>` + thiserror 枚举 | 异常类层次 → Err 变体;捕获点 → `?` 传播链的消费点 |
54
+ | 异常(编程错误) | `panic!`/`assert!` | 源系统把两类混在一起时,按契约区分:调用方会捕获处理的是业务错误 |
55
+ | errno / 返回码 | `Result` | |
56
+ | try/finally | RAII / `scopeguard` | |
57
+ | 裸 catch-all 吞异常 | 显式决定:记日志继续(契约如此)或去掉(记入 parity_exceptions) | 吞异常常是原系统 bug,走 ADR 裁决 |
58
+
59
+ ## 并发模型
60
+
61
+ | 源构造 | Rust 映射 | 备注 |
62
+ |--------|-----------|------|
63
+ | async/await(JS/Python/C#) | tokio + async/await | 单线程事件循环语义 ≠ tokio 多线程调度——共享状态从"天然安全"变为需要 `Arc<Mutex>`,数据竞争之外的**顺序假设**(回调按注册序触发等)逐个核对 |
64
+ | goroutine + channel | `std::thread`/tokio task + `mpsc`/crossbeam | 语义相近,最平滑的映射 |
65
+ | 线程 + 锁 | `std::thread` + `Mutex`/`RwLock` | Rust 强制锁保护数据,原系统"忘了加锁"的地方会被暴露——按契约行为裁决 |
66
+ | GIL 下的"线程安全" | 显式同步 | Python 线程的原子性假设在 Rust 不成立 |
67
+ | 回调风格异步 | async/await 重写,或 channel + 事件循环 | 控制反转正过来 |
68
+ | 定时器/事件循环 | tokio::time / 游戏固定 timestep | |
69
+
70
+ ## 函数式 / 动态特性
71
+
72
+ | 源构造 | Rust 映射 | 备注 |
73
+ |--------|-----------|------|
74
+ | 一等函数/闭包 | `Fn`/`FnMut`/`FnOnce` + 泛型或 `Box<dyn Fn>` | |
75
+ | 装饰器/高阶包装 | 显式包装函数、builder,或(仅横切关注点)宏 | 别急着写宏,多数装饰器就是函数组合 |
76
+ | 猴子补丁/运行时替换 | trait + 测试替身注入 | 补丁点即接缝,设计期显式化 |
77
+ | 反射/自省 | serde(数据形状)/ enum + match(行为分发) | "遍历字段"几乎都是序列化需求 |
78
+ | 元编程/代码生成 | 宏(声明式优先)/ build.rs | 成本高,先确认契约真的需要这个灵活性 |
79
+ | eval / 动态加载 | 解释器嵌入(rhai/rlua)或砍掉 | 契约层面裁决,多半进 parity_exceptions |
80
+ | 生成器/yield | `Iterator` 实现 / async Stream | |
81
+ | 列表推导/管道 | 迭代器链 | 天然映射 |
82
+
83
+ ## 全局状态与生命周期
84
+
85
+ | 源构造 | Rust 映射 | 备注 |
86
+ |--------|-----------|------|
87
+ | 全局单例 | 显式依赖注入(构造时传入)为主;确需全局用 `OnceLock` | 单例多为省参数——Rust 里传 `&Context` 更可测 |
88
+ | 模块级可变状态 | 所属 struct 的字段 | |
89
+ | 环境隐式依赖(cwd、env、时钟) | 显式参数/trait(`Clock`),边界处读取 | 这是 golden 测试可复现的前提 |
90
+ | 初始化顺序依赖 | 类型系统表达(构造函数返回已初始化的值;typestate) | "必须先 init"类 bug 在 Rust 编译期消失 |
91
+
92
+ ## 各源语言速查
93
+
94
+ - **JavaScript/TypeScript**:原型链→上面 OO 节;`this` 动态绑定→方法接收者显式化;npm 微依赖→多数用 std 替代;事件循环顺序假设→并发节
95
+ - **Python**:kwargs/默认参数→builder 或 Option 参数 struct;魔术方法→对应 trait(`__eq__`→PartialEq、`__iter__`→Iterator);鸭子类型→trait
96
+ - **Go**:接口→trait(几乎 1:1);error 返回→Result;`defer`→Drop;channel→mpsc/crossbeam
97
+ - **Java/C#**:继承层次→OO 节;注解/DI 容器→显式构造注入;stream/LINQ→迭代器
98
+ - **C/C++**:优先复用 c-to-rust 工作流的模式库(skills/c-to-rust-implement/references/);本工作流适用于"要重新设计架构"的场景,逐函数移植场景用 c-to-rust
99
+ - **Ruby/PHP**:动态特性最重,method_missing/魔术方法→设计期显式枚举全部实际用法(grep 调用点),为真实用法建模,不为机制建模