docs(eval): filesense ablation results — no measurable difference, and why - #422
Conversation
…d why First run with filesense as the only variable. The 2026-07-12 ablation had it enabled in **both** arms, so that data said nothing about it. **Result: 4/12 vs 4/12. All twelve tasks agree, arm for arm, category for category.** The cost of having it on was ~35K input / 47K output tokens and 27s per task. That is not "filesense is useless", and it is not evidence that it helps. Three limits are stated with the numbers: 1. **Only 8 of 12 tasks can discriminate.** The four query tasks fail in both arms for a reason unrelated to filesense — `planner.ts:151` routes query tasks around LLM planning entirely (#419), so nothing consumes what navigation produces. 2. **Two known defects suppress the measurable contribution, both unfixed** (#419, and #420 where a bare directory name lifted from the task text is used as a scan root — measured returning 0 entries once). 3. **Single run, n=12.** Too small to separate a small effect from noise. The one attributable observation, on the highest-precision navigation in the set (1 entry scanned out of 430 to locate `src/app/routes`): the off arm still passed, taking one extra step, 89 more seconds and 3.3K more output tokens, while the on arm spent 5.5K more input. A quantifiable trade, and not a favourable one at this task size. I also record the counter-sample: on `deep-create-checkout-hook` the on arm spent more input *and* more output for no gain. So "navigation trades input tokens for output tokens" — which I believed after the first data point — does **not** hold across this run. The zero is decomposed by category rather than left as "unmeasurable, therefore useless": query is blocked by #419, create had strong textual hints to the target (a flaw in my task design), bugfix is bottlenecked on codegen quality with localization working, refactor was simply easy enough. Next step is to fix #419/#420 and design tasks whose target location carries no textual hint. Raw JSONL for both arms committed alongside, so every number is recomputable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
代码评审报告: docs(eval): filesense ablation results — no measurable difference, and why
风险等级: 中
处理建议: 请求修改
决策摘要: 数据与统计全部复算通过(4/12 vs 4/12、422 条目、各项均值逐个吻合),但结论表里 bugfix 类的瓶颈归因与本 PR 自己提交的 JSONL 记录相矛盾,且失败清单存在被静默截断成不可执行的命令;改这两处即可合并。
级联分析
- 变更符号: 无导出符号。
benchmarks/eval/report-filesense.mjs是独立脚本(顶层console.log,无 export),仅改了模板字面量内的两行文案。 - 受影响流程: 手工运行的报告生成流程。
packages/**、apps/**未触及,运行时无影响。 - 变更集外调用方:
README.md:1333记录调用方式;scripts/tests/workflow-rules.test.mjs:617只断言 README 提到该文件名,不加载脚本(text search)。无其他引用。 - 置信度: medium(无代码图谱;调用方由 grep 确认,harness/夹具生成器已直接阅读复核;未能在本次评审中执行 node 复跑生成器)
问题发现
-
[中] bugfix 类的瓶颈归因与提交的原始记录相反
- 证据: 结论表写「代码生成质量,与定位无关(三条都触发了导航、也读到了源文件)」。但
full-deep.jsonl三条 bugfix 的agentError都是apply_patch指向不存在的文件:src/features/billing/lib/calculateAmount.ts(任务目标是src/features/checkout/lib/computeTotal.ts,见benchmarks/eval/tasks-deep.json:149,即跑错了 feature)、src/features/cart/lib/merge.ts(真实文件mergeLines.ts)、src/features/shipping/lib/estimateDeliveryTime.ts(真实文件estimateEta.ts)。JSONL 的eventDetails只含filesense/validationFailed/rollback,没有任何 read_file 记录,因此「也读到了源文件」既不能按 PR 承诺从提交数据复算,方向上也与记录相反。同族证据:deep-create-entity-guard开臂导航已明确warnings: ["Path does not exist: src/entities/coupon/lib"],agent 仍去 patch 该路径。 - 受影响调用方/流程: 该行是「零差异可拆解」这一核心主张的四分之一;后续「修 #419/#420 后重测」的优先级直接建立在它之上。
- 最小可行修复: 把瓶颈改为记录能支持的表述(如「apply_patch 目标文件名/所属 feature 判断错误,pre-execution 校验拦下」),或注明「读到源文件」的证据来自未提交的运行日志而非本 PR 的 JSONL。
- 证据: 结论表写「代码生成质量,与定位无关(三条都触发了导航、也读到了源文件)」。但
-
[中] 失败清单里的命令被静默截断成不可执行路径
- 证据: 报告中两处写作
cmd(npx vitest run src/features/checkout/lib/computeTotal.test.t),末尾s丢失。成因是report-filesense.mjs:208的String(c.detail).slice(0, 60):该命令恰为 61 字符,而 shipping 的 60 字符命令完整显示。截断没有省略号标记,读者无法察觉,照抄即得到不存在的测试路径。 - 受影响调用方/流程: 所有以该报告为复盘素材的后续排查;未来任何更长的
cmddetail 都会同样静默变形。 - 最小可行修复: 截断时追加
…标记,或对cmd类 detail 放宽上限。(208 行不在本次 diff,但失真产物由本 PR 提交。)
- 证据: 报告中两处写作
-
[中]
pnpm quality:precommit不覆盖本次修复的文件,不能作为该修复的验证证据- 证据:
biome.json:61的includes含"!!**/benchmarks",pnpm lint(biome check .)不解析benchmarks/eval/*.mjs;typecheck/test也不加载该脚本(grep 全仓仅 README 与 workflow-rules 的文本断言)。这正是一个模板字面量语法错误能存活至今的原因,也意味着 exit 0 与本次修复无关。 - 受影响调用方/流程: 该生成器的任何后续改动同样无自动化验证。
- 最小可行修复: 在 precommit 增加
node --check benchmarks/eval/*.mjs(或把benchmarks/**纳入 biome),并在 PR 验证栏说明本轮报告确由修复后的生成器手工跑出。
- 证据:
-
[低]
report-filesense.mjs:187的改动不是修复所必需,且降低产物质量- 证据: 176 行的反引号在模板字面量正文里,确实会提前闭合模板——该修复必要且正确。187 行的反引号位于
${...}内的单引号字符串中,是普通字符,不参与模板闭合;去掉后降级分支输出的plannerFallbackReason失去代码格式。 - 受影响调用方/流程: 仅降级分支文案(本轮未触发)。
- 最小可行修复: 恢复为
\`plannerFallbackReason\`。
- 证据: 176 行的反引号在模板字面量正文里,确实会提前闭合模板——该修复必要且正确。187 行的反引号位于
-
[低] 报告自述的两项校验在产物里不可见
- 证据: 开头写「filesense 的全部预算参数……已从 JSONL 校验」,但 JSONL 只记录
enabled/filesenseOutput/filesenseWriteMode(run-eval.mjs:288,其注释明说是请求值而非生效值);数值预算靠run-eval.mjs:84的环境变量断言,不在 JSONL 里。同段又称「下面的关臂零触发守卫会验证这一点」,而该守卫(report-filesense.mjs:90-98)只向 stderr 输出并 exit,报告正文没有任何一行显示它跑过——读者无法区分「守卫通过」与「守卫未跑/产物被手改」。属既有生成器文案,非本 PR 引入,但本 PR 将其作为证据提交。 - 最小可行修复: 措辞降级为「output/writeMode 已从 JSONL 校验,数值预算由 harness 启动断言保证」,并在报告里物化守卫结果(例如「关臂触发导航任务数:0/12」)。
- 证据: 开头写「filesense 的全部预算参数……已从 JSONL 校验」,但 JSONL 只记录
行级发现
- [benchmarks/results/2026-08-01-filesense-ablation.md:140] 「与定位无关……也读到了源文件」与三条 bugfix 的
agentError(patch 指向 billing/calculateAmount.ts、cart/merge.ts、shipping/estimateDeliveryTime.ts,均不存在)相矛盾,且 JSONL 无 read_file 记录;改为记录支持的「目标文件定位错误」表述,或标注证据来自未提交的日志。 - [benchmarks/results/2026-08-01-filesense-ablation.md:92]
computeTotal.test.t是report-filesense.mjs:208的slice(0, 60)截掉了末位s,命令不可执行;截断处补省略号或放宽cmddetail 上限后重新生成(第 100 行同因)。 - [benchmarks/eval/report-filesense.mjs:187] 此处反引号在
${}内的单引号字符串中,不会提前闭合模板,本次解析错误只来自 176 行;恢复\`plannerFallbackReason\`以保留降级分支的代码格式。
Karpathy 评审
- 假设: 「触发导航」被隐含当作「导航起作用」——
deep-create-checkout-hook触发但entries: 0,这点结论里已用 #420 明确披露,处理得当;未披露的假设是「bugfix 三条读到了源文件」。 - 简洁性: 生成器改动 2 行,无新增抽象;报告结构与既有
report.mjs分工在文件头注释里已说明。 - 结构质量: 无退化。新增文件为数据与文档,生成器仍 223 行、单一职责,未见薄 wrapper、重复 helper 或边界泄漏。
- 变更范围: 聚焦。唯一越界是 187 行的非必要改动(见发现 4)。
- 验证: 我按提交的 JSONL 逐条复算:通过率 4/12 vs 4/12 且逐任务一致、触发 10/12、累计条目 422、均值 42、截断 1、四类通过率与触发数、两臂 input/output/延迟均值(15086/25442/251s 与 12172/21496/224s)、总量差 ~35K/47K、+27s、
deep-refactor-route-title的 6/7 步与全部 token 数,以及「430 条目」(由fixture-deep/generate.mjs的 24×8+12×3+14 锚点文件推算:242 files + 187 dirs + src = 430)——全部吻合。未能在本次评审中执行 node 复跑生成器,语法修复系静态判读。
缺失覆盖
benchmarks/eval/*.mjs无任何 lint/解析/执行覆盖(biome 显式排除),本次这类语法错误无自动化手段可发现——建议 precommit 增加node --check。- 报告生成器无快照或单测:60 字符截断、零触发/泄漏守卫、降级分支文案均未被任何测试触达。
- 「430 条目」来自夹具生成器而非 JSONL,与 PR 所称「每个数字都可从提交的 JSONL 复算」不符;建议在报告中标出该数的出处。
| |---|---|---| | ||
| | query 0/4 | 相同 | #419——不走 LLM 规划,导航结果无人消费 | | ||
| | create 2/3 | 相同 | 目标位置在任务描述里线索较强,不导航也能猜对 | | ||
| | bugfix 0/3 | 相同 | 代码生成质量,与定位无关(三条都触发了导航、也读到了源文件) | |
There was a problem hiding this comment.
「与定位无关……也读到了源文件」与三条 bugfix 的 agentError(patch 指向 billing/calculateAmount.ts、cart/merge.ts、shipping/estimateDeliveryTime.ts,均不存在)相矛盾,且 JSONL 无 read_file 记录;改为记录支持的「目标文件定位错误」表述,或标注证据来自未提交的日志。
| - **[filesense 开] deep-query-format-convention**:result_contains(checkout:), result_contains(toFixed) | ||
| - **[filesense 开] deep-query-shared-lib**:result_contains(clamp), result_contains(formatDate), result_contains(pluralize) | ||
| - **[filesense 开] deep-create-entity-guard**:file_contains(isExpired) | ||
| - **[filesense 开] deep-bugfix-checkout-total**:cmd(npx vitest run src/features/checkout/lib/computeTotal.test.t) |
There was a problem hiding this comment.
computeTotal.test.t 是 report-filesense.mjs:208 的 slice(0, 60) 截掉了末位 s,命令不可执行;截断处补省略号或放宽 cmd detail 上限后重新生成(第 100 行同因)。
| arms.full.filter((r) => r.plannerFallbackReason).length > 0 || | ||
| arms.off.filter((r) => r.plannerFallbackReason).length > 0 | ||
| ? '**本轮存在降级任务,通过率不可直接引用**——降级把路径覆盖成硬编码值,与 filesense 是否定位成功无关。降级原因见各条记录的 `plannerFallbackReason`。' | ||
| ? '**本轮存在降级任务,通过率不可直接引用**——降级把路径覆盖成硬编码值,与 filesense 是否定位成功无关。降级原因见各条记录的 plannerFallbackReason。' |
There was a problem hiding this comment.
此处反引号在 ${} 内的单引号字符串中,不会提前闭合模板,本次解析错误只来自 176 行;恢复 \`plannerFallbackReason\` 以保留降级分支的代码格式。
Linked Issue Or Context
Result
4/12 vs 4/12. All twelve tasks agree arm for arm; every category matches.
Cost of having it on: ~35K input / 47K output tokens, +27s per task. Zero planner degradations in either arm.
What this does and does not support
It is not "filesense is useless", and it is not evidence that it helps. Three limits travel with the numbers:
planner.ts:151routes query tasks around LLM planning entirely ([Bug] query tasks never use LLM planning, so they can only read files the caller supplied #419), so nothing consumes what navigation produces.The one attributable observation
deep-refactor-route-title— the highest-precision navigation in the set, 1 entry scanned out of 430 to locatesrc/app/routes:The off arm still passed, taking one extra step, 89 more seconds and 3.3K more output; the on arm spent 5.5K more input. A quantifiable trade, and not a favourable one at this task size.
The counter-sample is recorded too: on
deep-create-checkout-hookthe on arm spent more input and more output for no gain. So "navigation trades input tokens for output tokens" — which I believed after the first data point — does not hold across this run.The zero is decomposed, not left as a shrug
"Unmeasurable, therefore useless" would have been the easy read. Next step is to fix #419/#420 and design tasks whose target location carries no textual hint.
Impact Scope
benchmarks/results/2026-08-01-filesense-ablation.md— the generated report plus a hand-written conclusion section, clearly marked as not generator output.benchmarks/results/2026-08-01-filesense/{full,no-filesense}-deep.jsonl— raw data for both arms, so every number is recomputable.benchmarks/eval/report-filesense.mjs— a template literal was closed early by a backtick-quoted path inside it; the generator could not parse. Fixed.GitNexus Impact Summary
benchmarks/matches no critical contract rule.packages/**orapps/**change, so no execution flows are affected. The report generator is invoked by hand.pnpm quality:precommitexit 0.Verification
pnpm quality:precommit— exit 0.fixture-deep, with all four report guards active (fixture/task-set provenance, off-arm zero-trigger, planner degradation, budget consistency). None fired, which is itself part of the result.Checklist
pnpm quality:precommit, or explained why it could not run.pnpm quality:localfor critical skeleton changes, or explained why it could not run — there are none.🤖 Generated with Claude Code