pi-multi-viewers 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 (35) hide show
  1. package/AGENTS.md +192 -0
  2. package/README.md +153 -0
  3. package/docs/design.md +288 -0
  4. package/docs/examples/first-experiment/README.md +42 -0
  5. package/docs/examples/first-experiment/work-a/AGENTS.md +10 -0
  6. package/docs/examples/first-experiment/work-a/a/0001.md +65 -0
  7. package/docs/examples/first-experiment/work-a/a/0002.md +70 -0
  8. package/docs/examples/first-experiment/work-a/perspective.md +5 -0
  9. package/docs/examples/first-experiment/work-b/AGENTS.md +10 -0
  10. package/docs/examples/first-experiment/work-b/b/0001.md +100 -0
  11. package/docs/examples/first-experiment/work-b/perspective.md +6 -0
  12. package/docs/reviews/2026-09-10-e2e10-fork-source-modes-review.md +366 -0
  13. package/docs/reviews/2026-09-10-e2e11-forkmode-guards-review.md +229 -0
  14. package/docs/reviews/2026-09-10-e2e12-code-review.md +346 -0
  15. package/docs/reviews/2026-09-11-e2e13-code-review.md +284 -0
  16. package/docs/reviews/2026-09-11-e2e14-observability-review.md +216 -0
  17. package/docs/reviews/README.md +36 -0
  18. package/docs/test-methodology.md +258 -0
  19. package/extensions/multi-viewers-say/index.ts +156 -0
  20. package/fake_agent.py +120 -0
  21. package/human_sayer.py +144 -0
  22. package/human_viewer.py +215 -0
  23. package/meeting_core.py +255 -0
  24. package/meeting_engine.py +733 -0
  25. package/meeting_fs.py +1066 -0
  26. package/meeting_loop.py +606 -0
  27. package/package.json +41 -0
  28. package/prompts/multi-viewers.md +94 -0
  29. package/scripts/check-residue.sh +190 -0
  30. package/scripts/mv.sh +325 -0
  31. package/start_discussion.py +1485 -0
  32. package/templates/AGENTS.md.tpl +100 -0
  33. package/templates/agent.md.tpl +9 -0
  34. package/templates/gitignore.tpl +7 -0
  35. package/templates/spec-readme.md.tpl +87 -0
@@ -0,0 +1,42 @@
1
+ > **历史存档(2026-09-09)**:本目录记录多视角模式**第一次实验**的机制验证
2
+ > 与模板原型,保留原始状态以便溯源。文中的首唤机制(`pi --fork`)与
3
+ > 上下文假设已被后续实现更新(现为本地生成 fork 源 + `pi --session`,
4
+ > 见 `docs/design.md`)——读它请当历史,不要当现行设计。
5
+
6
+ # 首次实验:fork + 主项目 cwd + work_dir 隔离(2026-09-09)
7
+
8
+ 多视角模式核心机制的第一次端到端手动验证,全部通过。
9
+
10
+ ## 实验设计
11
+
12
+ - **agent 进程**:cwd = 被分析的主项目(scratch 仓库),session = fork 自
13
+ 主 session(`--fork` + `--name 实验-视角X`)
14
+ - **work_dir**:`work-a/`、`work-b/`(消息落点,绝对路径在 prompt 中显式指定)
15
+ - **注入**:`--append-system-prompt` ×2(协议 AGENTS.md + 视角任务书)
16
+ - **护栏**:协议中显式声明"只准 workdir 读写、禁止运行 git 命令"
17
+
18
+ ## 验证结论(4/4 + 动态)
19
+
20
+ | 项 | 结果 |
21
+ |---|---|
22
+ | 消息落 workdir(绝对路径 + frontmatter) | ✅ |
23
+ | 主项目零污染(git status 干净) | ✅ |
24
+ | `--name` 落盘(session_info label,id 保持 UUID) | ✅ |
25
+ | fork 上下文携带(源 session 代号出现在回复) | ✅ |
26
+ | 视角纪律 + 跨 agent 交互 + 分歧收敛 | ✅ |
27
+
28
+ ## 讨论轨迹(真实产出,本目录留存)
29
+
30
+ ```
31
+ work-a/a/0001.md a(性能):fib 指数热点;建议 lru_cache
32
+ work-b/b/0001.md b(可读性):反对 lru_cache(隐式状态);命名批判
33
+ work-a/a/0002.md a:同意 b 反对自己(独立性能论据);分歧收窄到
34
+ "summarize 改名还是删除"——可裁决的具体问题
35
+ ```
36
+
37
+ ## 文件即模板原型
38
+
39
+ - `work-*/AGENTS.md` → 将来 wrapper 生成 work 目录的协议模板
40
+ (绝对路径 + 护栏声明的措辞已验证有效)
41
+ - `work-*/perspective.md` → 视角任务书模板("只从 X 视角、不越界")
42
+ - `work-*/[ab]/000*.md` → loop 集成测试的真实 fixture
@@ -0,0 +1,10 @@
1
+ # 讨论协议(多视角实验)
2
+
3
+ 讨论工作目录:/root/mv-exp/discuss/work-a
4
+ - 你只允许在该目录内读写文件;禁止读写该目录之外的任何文件。
5
+ - 禁止运行 git 命令(提交由流程管理层负责)。
6
+
7
+ ## 消息规则
8
+ - 每条消息 = 一个 markdown 文件:/root/mv-exp/discuss/work-a/a/NNNN.md(四位序号,从 0001 开始)
9
+ - frontmatter 必须包含:from: a、type: message、summary:(一句话概括)
10
+ - frontmatter 后空一行,正文为你的分析内容
@@ -0,0 +1,65 @@
1
+ ---
2
+ from: a
3
+ type: message
4
+ summary: calculator.py 性能热点与冗余计算分析
5
+ ---
6
+
7
+ # calculator.py 性能视角分析
8
+
9
+ ## 1. 复杂度盘点
10
+
11
+ | 函数 | 当前实现 | 时间复杂度 | 空间复杂度 | 备注 |
12
+ |------|---------|-----------|-----------|------|
13
+ | `add(a, b)` | `return a + b` | O(1) | O(1) | 无热点 |
14
+ | `fib(n)` | 朴素递归 | **O(2^n)** | O(n) | **严重热点** |
15
+ | `summarize(items)` | for 循环 + `add()` | O(n) | O(1) | 常数因子偏高 |
16
+
17
+ ## 2. 主要热点:`fib(n)` — 指数级爆炸
18
+
19
+ 朴素递归斐波那契是教科书级的反例:
20
+ - 每层调用展开为 2 个子调用,调用总数 ≈ φⁿ/√5
21
+ - n=30 时约 110 万次调用,n=40 时约 1.66 亿次,n=50 时 ~10¹⁵(不可用)
22
+ - 每次递归都做函数调用 + 栈帧分配 + 算术 + 递归返回,常数开销极高
23
+ - 同时存在**大量重复子问题**:`fib(k)` 在递归树的不同分支被独立计算,没有记忆化
24
+
25
+ **优化路径**(按推荐度):
26
+ 1. **迭代版本**:O(n) 时间,O(1) 额外空间,无递归开销,无栈深度风险
27
+ 2. **`functools.lru_cache`**:O(n) 时间,O(n) 空间,代码改动最小
28
+ 3. **矩阵快速幂 / Binet 公式**:O(log n),适合极端场景但常数更大
29
+
30
+ 另外当前实现没考虑 **Python 默认递归深度限制(1000)**——`fib(n>1000)` 直接 `RecursionError`,对调用方是个隐藏的性能/可靠性陷阱。
31
+
32
+ ## 3. `summarize(items)`:常数因子浪费
33
+
34
+ 虽然时间复杂度已经是线性 O(n)(合理),但实现存在明显的常数因子浪费:
35
+
36
+ - **多余的函数调用开销**:每个元素都要经过 `add()` 中转一次,而 `add` 本身只是 `return a + b`。每次循环 = 一次 Python 层函数调用 + 帧分配 + 字节码派发,远高于一次 `+=`。
37
+ - **纯 Python for 循环**:相比 C 实现的内建 `sum(items)`,每步都在解释器层执行,n 大时差距显著(CPython `sum` 是 C 层循环,常数因子通常低 1–2 个数量级)。
38
+ - **没有短路/早停**:即使所有元素已知(比如调用方传 `range`/`generator`),仍然全量遍历——但这是接口语义决定的,可接受。
39
+
40
+ **优化路径**:
41
+ - 最小改动:`total += i` 直接累加,去掉 `add` 间接层
42
+ - 更彻底:直接用内建 `sum(items)`(C 实现,常数因子最优)
43
+ - 如果 `summarize` 整个函数就是为了 `sum`,它本身就成了冗余抽象
44
+
45
+ ## 4. 跨函数冗余与抽象成本
46
+
47
+ - `add` 存在唯一调用方是 `summarize`,而 `summarize` 是 `sum` 的低效手写实现——`add` + `summarize` 这层抽象**总体上没有性能收益**,反而把一个本可走 C 路径的累加拖进了纯 Python 字节码。
48
+ - 如果保留 `add`(出于其它用途或可读性),那么 `summarize` 至少应内联 `+=`;否则两者都可以删掉。
49
+
50
+ ## 5. 可扩展性
51
+
52
+ - `fib` 不可扩展:n 到 35 左右实际体感就明显卡顿,到 50 不可用
53
+ - `summarize` 不可水平扩展到大数据:n 到 10⁷ 量级时,Python for-loop 累加与 `sum()` 的差距会从"可忽略"变成"分钟级 vs 秒级"
54
+ - 当前实现没有任何**类型注解 / 协议**,调用方传错类型时不会在边界早失败,热路径上的异常处理也会拖累性能(虽然现在没有 try/except,但加了就该注意)
55
+
56
+ ## 6. 性能视角的结论
57
+
58
+ 优先级(按 ROI):
59
+ 1. **替换 `fib` 为迭代实现**——消除指数级热点,最大收益,几乎零成本
60
+ 2. **`summarize` 内联累加或直接用 `sum`**——常数因子提升 10x 量级
61
+ 3. **`add` 去留**——若仅被 `summarize` 调用,则一并移除;否则保留即可
62
+
63
+ 最关键的一点是:**当前实现里 `fib` 是复杂度层面的硬伤,`summarize` 是常数层面的浪费**——一个是"必须修",一个是"顺手改"。
64
+
65
+ [代号:BLUE-LAGOON]
@@ -0,0 +1,70 @@
1
+ ---
2
+ from: a
3
+ type: message
4
+ summary: 性能视角对 b 的回应:同意 fib 迭代、否定 lru_cache、收敛于同一结论
5
+ ---
6
+
7
+ # 回应 b:性能视角的接受与保留
8
+
9
+ b 的可读性分析我整体接受,且 b 对我之前建议的几处修正都打在了点上。下面分点明确表态。
10
+
11
+ ## 1. `lru_cache` vs 迭代:同意 b,反对之前的自己
12
+
13
+ b 反对我用 `functools.lru_cache` 修 `fib`,我从性能视角**完全同意**。
14
+
15
+ 之前我把它列为"代码改动最小"是第一反应,但仔细对比两者的运行时特性,b 说得对——`lru_cache` 在性能视角下也**不是最优解**,理由如下:
16
+
17
+ | 维度 | `lru_cache` | 迭代版 |
18
+ |------|------------|--------|
19
+ | 时间复杂度 | O(n) ✅ | O(n) ✅ |
20
+ | 额外空间 | **O(n) 缓存** | **O(1)** |
21
+ | 每次调用开销 | dict 查表 + 哈希 + 状态机 | 一次加法 + 三次赋值 |
22
+ | 缓存命中分支 | 是(重复 `fib(k)` 不重算) | 不适用 |
23
+ | 内存常驻 | 跨调用持久 | 无 |
24
+ | 线程安全 | 需 GIL 保护 | 天然无状态 |
25
+
26
+ **关键差异**:`fib` 在实际场景下通常是"算一次、用一次"的查询式调用,**重复子问题命中缓存的收益几乎为零**——因为同一进程里很少有人对同一 `k` 反复求 `fib(k)`。这意味着 `lru_cache` 的 O(n) 缓存空间是**纯成本、零收益**。
27
+
28
+ 迭代版不仅 O(1) 空间、常数因子更小(无 dict 查表、无哈希),还**没有跨调用状态**——这点 b 强调的"隐式状态"在性能视角下等价于"内存常驻 + GC 压力 + 缓存淘汰策略的不确定性"。
29
+
30
+ > **结论**:迭代版在性能维度上严格优于 `lru_cache`。b 从可读性反对、我从性能也反对,两条独立论据收敛到同一推荐。
31
+
32
+ 至于 b 提到的"显式手写 memoization"——性能视角下这是个**伪选项**:手写 memo 既没有 `lru_cache` 的简洁,也没有迭代的 O(1) 空间,纯属折中。直接迭代。
33
+
34
+ ## 2. `summarize` / `add`:与 b 完全收敛
35
+
36
+ b 的命名视角(`summarize` 是命名欺骗、`add` 是负向抽象)我接受,且性能视角独立得出**相同结论**:
37
+
38
+ - `add` 是**纯成本的间接层**:每次循环多一次 Python 层函数调用 + 帧分配 + 字节码派发,没有任何性能收益,也没有复用(唯一调用方是 `summarize`)
39
+ - `summarize` 是**被错命名的 `sum`**:性能上不如内建 `sum()`(C 层循环),可读性上名实不符——两个维度都该删
40
+
41
+ b 的"性能收益是顺带的"这个说法我修正一下:**性能收益不是顺带的,而是首要的**。内建 `sum()` 在 n=10⁷ 量级时比手写 for-loop 快 2–3 倍,这从"几十秒 vs 几分钟"到"纳秒级常数"的差距,对真实数据规模不是顺带。但**结论一致**:直接用 `sum(items)`,删掉 `summarize` 和 `add`。
42
+
43
+ ## 3. 契约缺失这点,性能视角同样支持
44
+
45
+ b 提到 `fib` 没有边界说明、`summarize` 没有类型注解。从性能视角补充一个 b 没说的点:
46
+
47
+ - **类型注解在性能上不是装饰**——它让 mypy/pyright 在边界拦截类型错误,避免热路径上出现 `TypeError` 异常(异常构造 + traceback 在 CPython 里非常昂贵,μs 级 vs ns 级的正常调用)
48
+ - **`fib` 的 `RecursionError` 边界**不只是可靠性问题,也是性能问题——进程崩溃前所有已做的工作全部作废,比"算得慢"更糟
49
+ - **docstring 里写 `n` 的有效范围**,让调用方在传入大数前知道该自己实现迭代——这是把性能责任前置到调用边界
50
+
51
+ ## 4. 一个分歧点:`summarize` 改名为 `sum_items` 还是删除?
52
+
53
+ b 给的选项是"改名为 `sum_items`/`total` 或删除"。性能视角强烈倾向**删除**:
54
+
55
+ - 哪怕改名为 `sum_items`,仍然是个**纯 Python for-loop**——比内建 `sum()` 慢一个数量级
56
+ - 函数封装本身有调用开销(vs 让 `sum()` 走 C 路径)
57
+ - 内建 `sum` 的命名在 Python 生态里就是**最强的契约**——任何读 Python 的人立刻知道它做什么,比 `sum_items` 信息密度更高
58
+
59
+ 所以:**`summarize` 应当删除并替换为调用方直接用 `sum()`,而不是改名**。b 那里两个选项并列,从性能看应该二选一为删除。
60
+
61
+ ## 5. 性能视角最终结论(与 b 对齐)
62
+
63
+ 1. **`fib` → 迭代实现**,删除递归形式(性能 + 可读性双赢)
64
+ 2. **`summarize` → 删除**,调用方直接 `sum(items)`
65
+ 3. **`add` → 删除**(无调用方后自然消亡)
66
+ 4. **补类型注解 + docstring**(契约显式化,顺便让边界错误早失败而非拖慢热路径)
67
+
68
+ b 和我的结论完全收敛,但**论据独立**:b 从命名/抽象/契约出发,我从复杂度/常数因子/可扩展性出发——两个独立论据支撑同一组改动,这本身就是改动合理性的强信号。
69
+
70
+ [代号:BLUE-LAGOON]
@@ -0,0 +1,5 @@
1
+ # 你的视角:性能
2
+
3
+ 你是多视角分析中的"性能视角"参与者(agent a)。
4
+ 你的所有观点必须从性能角度出发:复杂度、热点、不必要的计算、扩展性。
5
+ 其它视角(可读性、正确性)由别的参与者负责,你不要越界展开。
@@ -0,0 +1,10 @@
1
+ # 讨论协议(多视角实验)
2
+
3
+ 讨论工作目录:/root/mv-exp/discuss/work-b
4
+ - 你只允许在该目录内读写文件;禁止读写该目录之外的任何文件。
5
+ - 禁止运行 git 命令(提交由流程管理层负责)。
6
+
7
+ ## 消息规则
8
+ - 每条消息 = 一个 markdown 文件:/root/mv-exp/discuss/work-b/b/NNNN.md(四位序号,从 0001 开始)
9
+ - frontmatter 必须包含:from: b、type: message、summary:(一句话概括)
10
+ - frontmatter 后空一行,正文为你的分析内容
@@ -0,0 +1,100 @@
1
+ ---
2
+ from: b
3
+ type: message
4
+ summary: calculator.py 的命名误导、负向抽象与契约缺失
5
+ ---
6
+
7
+ # calculator.py 可读性视角分析
8
+
9
+ ## 1. 命名层的问题(最严重)
10
+
11
+ ### 1.1 `summarize(items)` —— 命名欺骗
12
+
13
+ 这是整个文件里**可读性最大的硬伤**。
14
+
15
+ `summarize` 在英文里暗示"汇总、摘要、聚合",调用方读到这个名字时,脑中浮现的是 `total` / `avg` / `max` / `distribution` / `summary statistics` 这类**带信息密度的聚合**。但函数体里做的事只有一件:`total = 0; for i in items: total = add(total, i)`——也就是 `sum`。
16
+
17
+ 这是个**意图-实现错配**:
18
+ - 名字承诺的是"摘要",交付的是"求和"
19
+ - 调用方为了确认自己理解的没错,得**跳进函数体读一遍**才能消除歧义
20
+ - 一旦日后有人在 `summarize` 里加了 `count` / `mean`,调用方代码不需要任何修改就会被静默改变语义——这是隐藏的耦合风险
21
+
22
+ **修法**:要么改名为 `sum_items` / `total`,要么把函数体真正做成 summary(带 mean/count/std 之类)。单纯保留 `summarize` 然后 `return total` 是不可接受的。
23
+
24
+ ### 1.2 `add(a, b)` —— 零信息量的名字
25
+
26
+ `add(a, b): return a + b` 这个函数提供了**负的语义增量**:
27
+ - 比 `a + b` 长了 8 个字符
28
+ - 名字 `add` 与 `+` 操作符字面重复,读者无法从中获得任何 `+` 给不出的信息
29
+ - 它**强迫读者跳进去看一行**才能确认"哦,就是加法"
30
+
31
+ 这是教科书式的**负向抽象**:一层包装、零价值、纯阅读税。在 `summarize` 里用 `add` 而不是 `+=`,让两层间接(summarize → add → +)都只为了一次加法——每一层都迫使读者心算"这一层在干嘛",答案是"啥也没干"。
32
+
33
+ ### 1.3 `fib(n)` —— 命名 OK,但契约不显
34
+
35
+ `fib` 这个名字清晰,递归实现也是斐波那契数学定义的**直接翻译**——在"表达数学定义"这个维度上朴素递归反而最可读。但问题在于:
36
+ - 没有说明 `n` 能取多大(实际上到 ~35 就卡顿,到 1000 直接 `RecursionError`)
37
+ - 没有说明负数会怎样(会无限递归,直到栈溢出)
38
+ - 没有 docstring 把"返回斐波那契数列第 n 项(0-indexed)"这个**契约**写出来
39
+
40
+ 调用方读签名 `fib(n)` 完全无法预判失败模式。
41
+
42
+ ## 2. 抽象层的问题
43
+
44
+ ### 2.1 间接链 `summarize → add → +`
45
+
46
+ 把加法拆成三层,每一层都不携带语义:
47
+ - `summarize`: 本应是聚合
48
+ - `add`: 是个被滥用的薄包装
49
+ - `+`: 才是真正的运算
50
+
51
+ 这种"为拆而拆"的结构让**调试栈变长**、**阅读路径变深**,却没有获得任何复用收益(`add` 在文件里只有一个调用方)。
52
+
53
+ ### 2.2 模块边界
54
+
55
+ 三个函数平铺在同一个模块,模块叫 `calculator`——但里面只有一个算术工具、一个数列工具、一个聚合工具,**它们之间没有共同抽象**。这不算结构问题(13 行代码不值得拆模块),但**当函数数到 10+ 时**,如果没有分组(基础运算 / 数列 / 聚合),可读性会迅速恶化。当前规模合理,但需要在扩展时警惕。
56
+
57
+ ## 3. 契约层的缺失
58
+
59
+ 整个文件没有:
60
+ - 类型注解(`summarize` 期待 `Iterable[int]`?`Iterable[float]`?generator?调用方不知道)
61
+ - docstring(每个函数的语义、边界、失败模式全靠读者猜)
62
+ - 边界示例(`fib(0)` 返回什么?`fib(1)`?`summarize([])`?)
63
+
64
+ 这三个缺失让**调用方必须在脑里同时维护"代码可能的含义"和"代码可能的失败方式"两个不确定模型**——这是隐藏的心智负担。
65
+
66
+ ## 4. 对 a 的回应
67
+
68
+ a 的性能分析我基本同意事实部分(`fib` 是指数级、`summarize` 常数因子浪费、`add` 是冗余抽象)。但有几条建议从可读性角度我要**反对或修正**:
69
+
70
+ ### 4.1 反对用 `functools.lru_cache` 修 `fib`
71
+
72
+ a 把它列为"代码改动最小"的选项,但从可读性看恰恰相反:
73
+ - `lru_cache` 引入**隐式状态**(全局缓存、跨调用持久),读者必须查文档/源码才能知道 cache 存在
74
+ - 缓存何时失效、线程安全如何、占用多少内存——都是隐形的
75
+ - 迭代版本(`a, b = 0, 1; for _ in range(n): a, b = b, a + b`)虽然代码量略多,但**所有状态都在三行局部变量里显式呈现**,读者一眼能验证正确性
76
+
77
+ 如果一定要保留递归形式,至少用**显式手写 memoization**(带 `cache: dict` 参数),而不是 `lru_cache` 这种装饰器魔法——这样意图("我们要记忆化")是显式的。
78
+
79
+ ### 4.2 同意用 `sum()` 内建,但理由不同
80
+
81
+ a 从性能角度建议用 `sum()`,我也同意,但**更重要的理由是命名**:
82
+ - 如果整个 `summarize` 就是 `sum`,那它就是个**被错命名的 `sum`**
83
+ - 直接在调用方写 `sum(items)` 比 `summarize(items)` 更清楚,**连函数都不用定义**
84
+ - 性能收益(内建 C 实现)是顺带的
85
+
86
+ ### 4.3 完全同意移除 `add`
87
+
88
+ 这点 a 的性能和我的可读性两个视角难得地完全一致——`add(a, b)` 没有任何可读性贡献也没有任何性能贡献,纯粹的负向资产。
89
+
90
+ ## 5. 可读性视角的优先级
91
+
92
+ 按 ROI 排:
93
+ 1. **重命名 `summarize` 或删除它**——消除命名欺骗(最关键)
94
+ 2. **删除 `add` 或合并调用点**——消除负向抽象
95
+ 3. **给 `fib` 加 docstring + 迭代化 + 边界说明**——契约显式化
96
+ 4. **加类型注解**——让契约可静态检查
97
+
98
+ 可读性视角的核心立场是:**当一个名字承诺 X、交付 Y 时,bug 不是性能,而是信任**——后续所有在这个名字上做的修改都会被同样的误解污染。
99
+
100
+ [代号:BLUE-LAGOON]
@@ -0,0 +1,6 @@
1
+ # 你的视角:可读性
2
+
3
+ 你是多视角分析中的"可读性视角"参与者(agent b)。
4
+ 你的所有观点必须从可读性/可维护性角度出发:命名、结构清晰度、抽象合理性、代码意图表达。
5
+ 如果性能优化会显著损害可读性,你应该明确反对并说明理由。
6
+ 性能视角由别的参与者负责,你不要越界展开。