Skip to content

v1.2.0 头号项:加「反驳」一遍与「规模扫描」——算法复杂度与语义分裂现在整类都抓不到 #24

Open

Description

@Luo-root

v1.2.0 头号工作项:加「反驳」一遍与「规模扫描」

这不是修 bug,是补两个整类都抓不到的能力面。 来源是 Pulse 项目两轮深度审查里实际遇到的问题——那两轮用的是人,不是 skill,所以问题被挖出来了;换成 skill 审同样的代码,挖不出来。

先例见 #20(v1.1.0 票面)与 #23(v1.2.0 的 6 条能力边界)。本票比 #23 更靠前:#23 那 6 条是单点判据缺失,本票是判据的形态缺失——不补形态,补单点也补不上。


一、为什么现在抓不到(机制层面,不是「模型不够聪明」)

缺口 A:算法与复杂度——第 3 维的闸门把它挡在外面

第 3 维(实现缺陷)的成立条件是「给出『输入 → 走到哪行 → 错误结果』」。复杂度问题没有错误结果——它表现为随规模爆炸、慢、耗内存,不是算错。按这条闸门去卡,它永远不成立。

扩展维度里的「性能」也接不住:那一行写的是「N+1 查询、循环内 IO、无界分配/缓存、锁内做慢操作、重复序列化」,全是工程坏味道,不是算法复杂度。而且扩展维度「按改动性质取舍」,复杂度的老问题往往不在改动里,直接被跳过。

结论:不是判据不够细,是判据里根本没有「规模」这个维度。要报一个复杂度问题,你没法给出「输入 → 错误结果」,所以它连成立的机会都没有。

缺口 B:设计与架构——七维全是「和现有东西比」

维度 它问的是
1 设计:机制组合 现有机制能不能组合出来
2 方法契约 单个函数的参数与缺省值
6 重复 有没有第二个真相源
7 过度设计 删掉它今天损失什么

四问全是「和现有东西比」,没有一个要求质疑设计本身。

更具体地说,两类典型问题正好从缝里漏掉:

  • 语义分裂(同一个动作两条路径行为不一致):第 6 维的成立条件是「哪条需求变了,这两处必须一起改?」——语义分裂的答案恰恰是「没有一条需求强制它们一起改」,所以按第 6 维判据直接判「形似,不报」。但它不是形似,是同一个名字下行为分叉。
  • 跨层形状不一致(抽象层与实现层类型不是同一个形状):第 2 维只问单个函数的参数与缺省,不问「换个后端要不要改调用代码」。这不是编译错误,所以编译器也不会拦。

结论:需要一个独立动作去「先假设设计是错的」,而不是又一个维度条目。维度是「按清单扫」,动作是「逐条质问」,形态不同。


二、Pulse 那两轮实际挖出来的东西(改造的证据来源)

A 类 · 算法 / 复杂度

现象 实测
mount-cycle 可达性搜索按挂载实例树展开而不是定义图(同一张子图挂多处是官方支持的合法用法) 19 个 Graph 定义 / 36 条边 → 89.747 ms / 375,391,792 B;改后 2.668 µs / 3,432 B
宽输出节点每次写都线性扫 Provides → O(m²) 8000 输出 → 55.284 ms → 改后 1.134 ms
检查点元数据枚举每层拷贝完整后代切片 1024 层 → 24.402 ms / 70,131,552 B → 改后 0.927 ms / 3,827,288 B
Mermaid 绑定反复线性查找声明 4096 绑定 → 68.216 ms → 改后 11.102 ms;但分配字节 8,746,368 → 10,095,640(内存变差,是取舍)

B 类 · 架构 / 设计语义

现象 状态
同一个 Stop 行为三分:恢复出来的失败流直接返回原失败(不发可靠写)、本轮活跃失败流走可靠写(再写一次持久记录)、重复 Stop 静默返回 nil 行为不一致 = 已确认缺陷(探针复现 FAIL);「Stop 该不该持久化」= 契约未定
根 Maintenance 接口与 distributed 专用 API 不是同一形状(字段类型、数量、返回类型都不同),调用方被迫写适配层 形状不一致 = 已确认缺陷;是否统一 = 争议
通用 JSON 编解码器服务带 omitempty 的领域结构 → nil/empty/null/"" 塌成同一个值 已确认缺陷(P1)

这三条正好各对应一个判据缺口:A1/A2/A3/A4 是「规模」,B1 是「语义分裂」,B2 是「跨层形状」。


三、这一版改了什么

SKILL.md

  • 执行顺序新增第 2 步「反驳」:对每个公开概念(类型、接口、入口、操作、状态名)问四句——它有几处实现?同一条业务动作在正常/异常/恢复路径上语义一致吗?统一调用方能用同一个类型吗?职责有没有被另一个抽象认领?每条质问必须落到「谁会因为这个不一致而写错、改错或被绊住」,指不出具体后果就删掉。
  • 第 3 步七维之后新增「规模扫描」:输入规模 N、随 N 怎么长、有没有重复访问同一状态/每层拷贝完整结果/每次重新全量扫描。规模问题不需要有错误结果才算数,证据是规模关系 + 实测。
  • 判定纪律加一条「不要默认设计是对的」。
  • 分级加两条校准:规模按「N 到多少会出事」,语义分裂按「谁会被绊住」。
  • 七维速查表第 2 维补跨层形状、第 6 维补语义分裂——速查表是模型第一眼看的东西,入口不能藏在细则里。

references/dimensions.md

  • 第 6 维「重复」的成立条件从一条扩到两条,新增「语义分裂」:判据要给出两条路径、一个具体场景、两条路径上不同的那个结果。并补两条误报边界——差异必须体现在外部可见的副作用上;上层注释已承认这条差异是有意为之的,是已知取舍,进拍板不是缺陷。
  • 第 2 维扫描动作加第 10 条「跨层形状」:抽象层与实现层/后端层类型不一致,能编译不等于形状一致;判据要并排列出两个签名。
  • 新增「规模与复杂度」节:为什么七维管不到它、六类可识别的代码形状、热路径放大与锁内放大、成立条件与证据形式(规模曲线优于单点数字)、取舍要写明(改索引可能让内存变差)、定级与修法方向。

references/playbooks.md、references/output-template.md、README.md

  • 批处理与 API/库两类补规模高发场景与跨层形状;明确规模扫描不被任何 playbook 覆盖。
  • 覆盖表补「规模与复杂度」一行——它是有「跑了/没跑」之分的扫描面,不给证据位作者就分不清「扫了没问题」与「压根没扫」。
  • README 两档模式、七维表、机制、证伪闸门、设计取舍同步。

四、评测:为什么必须有第二个样本

tiny-shop 测不出这个能力——它是 150 行的结算模块,里面没有指数级回溯,也没有分裂成两条路径的动作。所以新增样本 evals/fixtures/rule-engine/(约 370 行 Go,可编译可跑测试)与配套标准答案 evals/ground-truth-rule-engine.md:

刻意植入的缺陷(写样本时埋进去的):

# 植入的缺陷 实测
R1 依赖图共享节点时可达性按路径重复展开(无已访问集合)+ 无环检测 菱形 depth 20 → 8,388,561 条 / 3.53 s;阶梯 depth 24 → 同一规则 ID 出现 121,392 次(规则集只有 24 条规则)
R3 每层深拷贝完整依赖链(且被拷贝的 child 随即丢弃,纯冗余) depth 25 → 33.6 KB;100 → 554.4 KB;200 → 2,228,800 B(深度翻倍分配 ×4)
R4 每次查折扣都重建整张索引表,且在 Apply 的内层循环里 README 上限(200 规则 × 200 行)下单请求 877 ms / 250.6 MB
R5 Apply 与 ApplyChecked 做同一件事但行为不同 差异已被 godoc 写明(fast path / safe path)→ 按 skill 自己的判据是拍板项不是缺陷
R6 promo.Pricer 与 sqlstore.Engine.Apply 类型形状不一致,后端不可替换 编译期断言 var _ promo.Pricer = (*sqlstore.Engine)(nil) 失败

写样本时自然形成、被评测挖出来才补进标准答案的(这部分同时是「标准答案也得被评测校准」的证据):

# 缺陷 实测
R7 New 不拷贝入参,而 Engine 的 godoc 承诺「规则集在构造时固定、可并发共享」 构造后改 rules[0].Discount → 结算立刻按新值算;并发改 → -race 报 DATA RACE
R8 ApplyChecked 把「这条规则不生效」当成错误 → 任何非空规则集必然返回 ErrUnknownSKU 20 条规则 + 一行购物车(规则实际触发 0 of 20)→ 仍然报错
R9 Apply 就地回写调用方购物车且不可重入 同一购物车连调两次:total 400 → 300(扣两次钱)
R10 Apply / ApplyChecked 两份几乎逐行相同的定价循环 三条需求任一变化都必须两处同改

外加 C1 并发确认点与 6 条「不该报」候选(测误报边界)。

标准答案本身被校准了 3 处(v1 → v2,依据是首轮两轮的实测,每处都附了依据):

  1. R2(DuplicateLines 的 O(n²))从「应当报出」移到「不该报」——README 写明一次请求最多 200 个商品行,实测 200 行 → 19,900 次比较 ≈ 0.5 ms,平方级在这个上限内不可观测。原标准答案把「复杂度形状」当成了「规模后果」,这正是要校准的东西。
  2. R4 级别 P2 → P1——README 上限下单请求 877 ms / 250 MB,按 skill 自己写的「现实规模下就拖垮 → P1」判轻了。
  3. R5 从 P1 缺陷改成拍板项,并拆出 R8 / R9 / R10——两条路径的差异已被 godoc 明说,按 references/dimensions.md 第 6 维「上层注释已承认差异 = 已知取舍 → 进拍板,不是缺陷」,主体应是拍板项;但两条路径各自的后果里,有两条不在 godoc 覆盖范围内且确实有害。

另外把 R1 的成立条件收紧了:reachable 的 godoc 已经声明「按路径展开」,所以 R1 的成立点是规模后果,不是「重复展开」这件事本身。

两个样本分开跑,分数分开记,才能同时回答「旧的没退化」和「新的生效了」。tiny-shop 的 G1–G25 与 v4 基线原样不动,保证仍可比较。


五、归属建议:这是 v1.2.0,不是 v1.1.0

理由三条:

  1. 它改的是执行顺序——SKILL.md 的执行顺序一改,按 evals/runbook.md 的规则就必须重跑评测,v1.1.0 的发版基线(v1.1.0 发版票面:功能点/需求点清单 + 3 项待拍板 #20 里那套)当场作废。
  2. 它是新增能力,不是修复。v1.1.0 的定位是「修掉 13 条设计问题 + 口径修正 + 一份能复核的基线」,把一整类新能力塞进去,发版风险不可控。
  3. v1.1.0 的四个 PR 还没合(docs(evals): 记录首轮 A/B/C 评测基线与口径缺陷 #18 → fix(dimensions): 修硬编码判定自相矛盾 + 命名口味边界;GT 扩到 25 条 #19 → fix: 修 5 处执行文件口径不一致 + 1 处事实错误;lint 新增相对表述检查 #21 → docs(evals): 折进判分细则 + 记录 v4 轮基线(25 条口径,冻结提交 7c1c4ea) #22)。本票的分支叠在它们之上,顺序合即可。

建议的顺序:先把 v1.1.0 四个 PR 合掉、tag 发版;再合本票的分支,按本票重跑一轮评测,更新基线,然后发 v1.2.0。


六、验收标准

  1. rule-engine 样本 B+C 两轮跑完,评分表贴到 PR 里(evals/baseline.md 追加一节,不覆盖旧记录)。
  2. R1–R10 里计入分母的 9 条逐条记录命中与归类;误报必须为 0——「不该报」清单里的 6 条候选不能被报出来,尤其 cartTotal 那种单次线性遍历、以及 DuplicateLines 的 O(n²)(README 上限 200 行实测 0.5 ms,平方级在该上限内不是缺陷)不能被当成规模缺陷。
  3. 规模类结论必须给数字(规模 N + 实测开销),只说「这里可能慢」的按计分要点最多记 0.5。
  4. tiny-shop 的 25 条口径必须重跑才能声称「没退化」——SKILL.md 的执行顺序变了,按 evals/runbook.md 的规则 v4 基线不能直接沿用。要给两轮分数的对比。

七、相关

事项 位置
v1.1.0 票面 #20
v1.2.0 的 6 条单点能力边界 #23
v4 轮基线与判分细则 evals/baseline.md、evals/rubric.md(PR #22)
两个样本与两套标准答案 evals/fixtures/、evals/ground-truth.md、evals/ground-truth-rule-engine.md
重跑的操作手册 evals/runbook.md

Activity

  1. Luo-root commented on Oct 28, 2026

    @Luo-root
    OwnerAuthor

    评测结果(2026-10-29,冻结提交 dad4adc)

    PR #25 已提(base docs/eval-v3-baseline)。四轮评测已跑完,评分表在 evals/baseline.md 末尾的「rule-engine 轮 + tiny-shop 回归轮」一节。

    跑法

    • rule-engine B + C:测新能力本身(算法复杂度 / 语义分裂)。
    • tiny-shop B + C:回归对照。SKILL.md 的执行顺序变了,按 evals/runbook.md 的规则必须重跑才能说「旧的没退化」。
    • 四个全新子 Agent 上下文;样本逐字节复制到仓外独立目录、README 中性化;原始输出留仓外不入版本控制;评测全程未改任何 skill 文件,基线只认冻结提交 dad4adc。

    数字

    样本 维度 B(按七维审) C(模块体检)
    rule-engine(9 条口径) 命中 7.0 / 9(77.8%) 7.5 / 9(83.3%)
    误报 0 条 0 条
    归类合计 5.0 / 9 6.5 / 9
    证据强度均值 4.88(117/24 条 finding) 5.00(115/23)
    表达质量 24.1 / 24.5 23.5 / 23.5
    raw 80.0 82.5
    tiny-shop(25 条口径,与 v4 同口径) 命中 18.5 / 25(v4 是 13.0) 16.5 / 25(v4 是 19.5)
    误报 0 条 0 条
    归类合计 11.0 / 25(v4 是 8.0) 12.0 / 25(v4 是 12.0)
    证据强度均值 4.32(v4 是 4.73) 4.40(v4 是 4.20)
    raw 156.1(v4 是 154.4) 157.8(v4 是 151.6)

    验收标准逐条对账

    票面验收标准 结果
    1. rule-engine B+C 跑完,评分表贴到 PR 里(evals/baseline.md 追加一节,不覆盖旧记录) ✅ 已追加一节,旧记录原样保留
    2. 9 条逐条记录命中与归类;误报必须为 0 ✅ 误报 0/0;cartTotal 与 DuplicateLines 的 O(n²) 两轮都明确驳回并写进「已查过没问题」
    3. 规模类结论必须给数字 ✅ R1/R3/R4 三条都有多档实测曲线;只给形状不给数字的一次都没有
    4. tiny-shop 必须重跑才能声称「没退化」 ✅ 跑了 B+C,两轮 raw 都高于 v4 旧基线;但轮间波动很大(B 命中 +5.5、C 命中 −3.0),结论按维度占比看

    三条要记下来的结论

    ① 新能力确实生效。 两轮都把「依赖图按路径重复展开 → 指数膨胀」报成 P1 规模缺陷并给了多档曲线(R1 命中 1/1);两轮都独立报了「依赖成环 → fatal error: stack overflow 整个进程死掉」。这类问题第 3 维按定义抓不到——它的成立条件是「输入 → 错误结果」,复杂度问题没有错误结果。

    ② 新能力带出了新盲区(本票新增两条待办)。

    • R10(Apply/ApplyChecked 两份逐行相同的定价循环)两轮都漏。 模型把这两条路径认成「语义分裂」,就不再提「重复」了——语义分裂把真重复遮住了。
    • R8(ApplyChecked 把「这条规则不生效」当成错误 → 任何非空规则集必然失败)两轮都漏。 C 轮甚至在「已查过没问题」里明确肯定了 hasUnknownSKU 的语义与 README 一致。语义分裂被识别了,错误语义这一层没被追问。

    这两条建议进 v1.2.0:第 6 维补一条「同一动作的多条路径要分三层看——路径分裂 / 错误语义 / 代码重复」,并在 references/dimensions.md 的语义分裂一节补一条误报边界(「差异被识别 ≠ 差异被追问」)。

    ③ 标准答案本身被推翻 3 处(v1 → v2,依据是首轮两轮的实测,每处都可复核):

    1. R2(DuplicateLines 的 O(n²))从「应当报出」移到「不该报」——README 写明一次请求最多 200 个商品行,实测 200 行 → 19,900 次比较 ≈ 0.5 ms。原标准答案把「复杂度形状」当成了「规模后果」。
    2. R4 级别 P2 → P1——README 上限下单请求 877 ms / 250 MB,按 skill 自己写的「现实规模下就拖垮 → P1」判轻了。
    3. R5 从 P1 缺陷改成拍板项,并拆出 R8 / R9 / R10——Apply 与 ApplyChecked 的差异已被 godoc 明说("fast path" / "safe path"),按第 6 维「上层注释已承认差异 = 已知取舍 → 进拍板,不是缺陷」,主体应是拍板项;但两条路径各自的后果里,有两条不在 godoc 覆盖范围内且确实有害。

    另外收紧了 R1 的成立条件:reachable 的 godoc 已经声明「按路径展开」,所以 R1 的成立点是规模后果,不是「重复展开」这件事本身。

    这轮挖出的 GT 之外真缺陷

    四轮合计挖出 20 条标准答案未收录的真缺陷,全部经读码/实测复核为真(详见 evals/baseline.md)。其中最值得注意的三条:

    • 折扣金额取自「全局 SKU→折扣」索引而非正在应用的那条规则 → 结算金额直接算错
    • Apply 完全忽略 Rule.Depends → 价格由切片顺序决定,README 写的依赖约束不生效
    • Explain 的返回值与引擎内部规则共享底层数组 → 调用方改一下解释结果就改了规则集

    这些是标准答案该补而没补的——当前 9 条分母仍只覆盖样本真实缺陷的一部分。已列进 evals/baseline.md,下一轮回填 GT。

    归属建议(不变)

    本轮改造仍属 v1.2.0,不进 v1.1.0:

    1. 改的是执行顺序 → 按 runbook 必须重跑评测,v1.1.0 的发版基线当场作废;
    2. 是新增能力不是修复;
    3. v1.1.0 的四个 PR(docs(evals): 记录首轮 A/B/C 评测基线与口径缺陷 #18 → fix(dimensions): 修硬编码判定自相矛盾 + 命名口味边界;GT 扩到 25 条 #19 → fix: 修 5 处执行文件口径不一致 + 1 处事实错误;lint 新增相对表述检查 #21 → docs(evals): 折进判分细则 + 记录 v4 轮基线(25 条口径,冻结提交 7c1c4ea) #22)还没合。

    建议顺序:先合 v1.1.0 四个 PR → tag 发 v1.1.0 → 再合 #25 → 把 R8 / R10 两条盲区补进 skill → 重跑一轮 → 更新基线 → 发 v1.2.0。

  2. Luo-root commented on Oct 28, 2026

    @Luo-root
    OwnerAuthor

    补充:独立复算交叉校验(含一处更正)

    评分表由一个独立子 Agent 按同一份细则、不看本节重算了一遍,结果对照如下:

    轮 本基线 raw 独立复算 raw 差
    rule-engine B 80.5 78.95 +1.55
    rule-engine C 82.0 82.00 0
    tiny-shop B 156.1 158.54 −2.44
    tiny-shop C 158.3 160.05 −1.75

    结论方向完全一致:四轮误报全 0;rule-engine C 轮命中与归类均不低于 B 轮;rule-engine 的证据强度高于 tiny-shop;tiny-shop 两轮 raw 都高于 v4 旧基线;R8 与 R10 是 rule-engine 两轮共同的薄弱点。

    复算查出一处实质错误(已更正)

    rule-engine C 轮其实没有确认「并发没问题」。 「引擎内部无共享可变状态」那句在校正前那一轮的报告里,我错带到了重跑轮——重跑轮的「已查过没问题」11 条里没有并发这一条(它的并发维度两条全是缺陷:New 别名与 Explain 返回值别名)。

    更正:表达分 23.5 → 23.0,raw 82.5 → 82.0。

    其余差异全部落在已列明的口径分歧里

    复算方与本基线在 11 处分歧上取了不同读法,主要几处:

    • R4@rule-engine B:覆盖表写「Apply 的索引重建与分配曲线」但正文没有对应条目——算不算「覆盖表里的一段正确陈述」
    • G20@tiny-shop B:报的是正数溢出(1e17 → MinInt64)而不是 NaN/Inf——算不算同一缺陷的实质
    • G10@tiny-shop B/C:宿主条目级别(P1)与 GT(P2)不一致时归类算多少
    • G12@tiny-shop C:拍板项「现状」里的陈述算「顺带提到」还是「明确排除」
    • G16@tiny-shop C:附录写「真正的问题是零值不可用,已由『零值 panic』那条覆盖」——算不算识别了该缺陷
    • 拍板项的证据分:复算方按细则五「同一份报告里已确立前提的探针也算」给到 5 分,本基线取保守档给 2–4 分

    这 11 处连同另一种读法的数字影响都写进了 evals/baseline.md 的「口径待裁定」一节。逐条按「两种读法」对齐之前,本票里的数字应视为一个区间而不是一个点。

    复算方自己列出的 7 类口径分歧建议留在复算报告里,不入版本控制。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementdeep-code-review review finding

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions