niceeval 0.11.3 → 0.11.4-canary.12

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 (41) hide show
  1. package/dist/i18n/zh-CN.js +1 -1
  2. package/dist/report/components/metric-views/compute.js +1 -1
  3. package/dist/report/components/metric-views/index.d.ts +2 -2
  4. package/dist/report/components/metric-views/index.js +2 -2
  5. package/dist/report/model/types.d.ts +1 -1
  6. package/dist/results/types.d.ts +1 -1
  7. package/dist/runner/types.d.ts +6 -6
  8. package/dist/shared/aggregate.d.ts +1 -1
  9. package/dist/shared/aggregate.js +2 -2
  10. package/docs-site/zh/README.md +1 -1
  11. package/docs-site/zh/explanation/runner.mdx +8 -1
  12. package/docs-site/zh/reference/cli.mdx +1 -1
  13. package/docs-site/zh/reference/report-components.mdx +6 -6
  14. package/docs-site/zh/reference/results-data.mdx +3 -3
  15. package/docs-site/zh/tutorials/agent-feedback-loop.mdx +7 -2
  16. package/docs-site/zh/tutorials/custom-reports.mdx +3 -3
  17. package/docs-site/zh/tutorials/scoring-guide.mdx +1 -1
  18. package/docs-site/zh/tutorials/viewing-results.mdx +6 -6
  19. package/package.json +5 -3
  20. package/src/agents/shared.ts +1 -1
  21. package/src/cli.ts +2 -2
  22. package/src/context/context.ts +1 -1
  23. package/src/i18n/zh-CN.ts +1 -1
  24. package/src/report/components/compute.test.ts +1 -1
  25. package/src/report/components/metric-views/MetricBars.tsx +1 -1
  26. package/src/report/components/metric-views/compute.ts +1 -1
  27. package/src/report/components/metric-views/delta-table.test.ts +2 -2
  28. package/src/report/components/metric-views/index.tsx +2 -2
  29. package/src/report/model/types.ts +1 -1
  30. package/src/results/select.test.ts +1 -1
  31. package/src/results/types.ts +1 -1
  32. package/src/runner/feedback/human.ts +3 -3
  33. package/src/runner/feedback/reducer.ts +1 -1
  34. package/src/runner/run.ts +2 -2
  35. package/src/runner/types.ts +6 -6
  36. package/src/shared/aggregate.ts +2 -2
  37. package/src/show/compose.ts +1 -1
  38. package/src/show/index.ts +2 -2
  39. package/src/show/show.test.ts +2 -2
  40. package/src/view/data.ts +1 -1
  41. package/src/view/shared/types.ts +1 -1
@@ -75,7 +75,7 @@ export const zhCN = {
75
75
  " --teardown 强杀后补收尾:只对选中的实验各执行一次 teardown(不派发\n" +
76
76
  " attempt、不跑 setup);与 eval id 前缀组合是用法错误\n" +
77
77
  " niceeval show [eval-id 前缀… | @<locator>] 终端读结果\n" +
78
- " 不带证据 flag:命中范围的榜单(裸跑、eval id 前缀、单个 --exp 都落在这里);\n" +
78
+ " 不带证据 flag:命中范围的默认报告(裸跑、eval id 前缀、单个 --exp 都落在这里);\n" +
79
79
  " 两个以上 --exp 改为逐条件对照\n" +
80
80
  " @<locator> 精确一个 attempt:无 flag → 紧凑全景;带 flag → 对应证据切面\n" +
81
81
  " --source 该 attempt 运行时保存的 Eval 源码,断言标回源码行\n" +
@@ -441,7 +441,7 @@ async function buildDeltaCell(items) {
441
441
  return {
442
442
  scoring,
443
443
  verdict,
444
- // totalScore 是题目级挣分(各 attempt 均值,与榜单 totalScore 指标同一套 perEval 聚合);
444
+ // totalScore 是题目级挣分(各 attempt 均值,与默认报告 totalScore 指标同一套 perEval 聚合);
445
445
  // totalTokens / totalCostUSD 是该题在该条件下全部 attempt 的合计,不是均值。
446
446
  ...(scoreCount > 0 ? { totalScore: scoreSum / scoreCount } : {}),
447
447
  attempts: [...refs].sort(),
@@ -15,7 +15,7 @@ export type MetricTableProps = DataProps<TableData, MetricTableOptions, ChromePr
15
15
  filter?: boolean;
16
16
  attemptHref?: (locator: AttemptLocator) => string;
17
17
  }>;
18
- /** 榜单:一行一个维度值、一列一个指标,回答「谁整体更好」。 */
18
+ /** 指标表:一行一个维度值、一列一个指标,回答「谁整体更好」。 */
19
19
  export declare const MetricTable: ReportComponent<MetricTableProps>;
20
20
  export type MetricMatrixProps = DataProps<MatrixData, MetricMatrixOptions, ChromeProps & {
21
21
  attemptHref?: (locator: AttemptLocator) => string;
@@ -23,7 +23,7 @@ export type MetricMatrixProps = DataProps<MatrixData, MetricMatrixOptions, Chrom
23
23
  export type MetricBarsProps = MetricMatrixProps;
24
24
  /** 逐题格子:行 × 列两个维度、格子里一个指标,回答「哪道题谁挂了」。 */
25
25
  export declare const MetricMatrix: ReportComponent<MetricMatrixProps>;
26
- /** 分组条形:同一份矩阵数据的另一种摆法;与 MetricMatrix 写同一份 spec 时只计算一次。 */
26
+ /** 分组柱状:同一份矩阵数据的另一种摆法;与 MetricMatrix 写同一份 spec 时只计算一次。 */
27
27
  export declare const MetricBars: ReportComponent<MetricBarsProps>;
28
28
  export type ScoreboardProps = DataProps<ScoreboardData, ScoreboardOptions, ChromeProps & {
29
29
  attemptHref?: (locator: AttemptLocator) => string;
@@ -325,7 +325,7 @@ export const validateStabilityMatrixData = (data) => {
325
325
  }
326
326
  return null;
327
327
  };
328
- /** 榜单:一行一个维度值、一列一个指标,回答「谁整体更好」。 */
328
+ /** 指标表:一行一个维度值、一列一个指标,回答「谁整体更好」。 */
329
329
  export const MetricTable = makeDataComponent({
330
330
  name: "MetricTable",
331
331
  dataFnName: "metricTableData",
@@ -347,7 +347,7 @@ export const MetricMatrix = makeDataComponent({
347
347
  web: (props, ctx) => (_jsx(MetricMatrixWeb, { data: props.data, locale: props.locale ?? ctx.locale, attemptHref: hrefOf(props, ctx), className: props.className })),
348
348
  text: (props, ctx) => matrixText(props.data, ctx),
349
349
  });
350
- /** 分组条形:同一份矩阵数据的另一种摆法;与 MetricMatrix 写同一份 spec 时只计算一次。 */
350
+ /** 分组柱状:同一份矩阵数据的另一种摆法;与 MetricMatrix 写同一份 spec 时只计算一次。 */
351
351
  export const MetricBars = makeDataComponent({
352
352
  name: "MetricBars",
353
353
  dataFnName: "metricMatrixData",
@@ -231,7 +231,7 @@ export interface ScoreboardData {
231
231
  }>;
232
232
  }
233
233
  /**
234
- * `DeltaTable` 的一格:同一条件值 × eval 的折叠(docs/feature/reports/components/tables/delta-table.md)。`verdict` / `totalScore` 用与榜单同一套题目级判定口径(`totalScore` 取各
234
+ * `DeltaTable` 的一格:同一条件值 × eval 的折叠(docs/feature/reports/components/tables/delta-table.md)。`verdict` / `totalScore` 用与默认报告同一套题目级判定口径(`totalScore` 取各
235
235
  * attempt 的均值);`totalTokens` / `totalCostUSD` 是该题在该条件下全部 attempt 的**合计**,
236
236
  * 不是均值。
237
237
  */
@@ -198,7 +198,7 @@ export interface Results {
198
198
  }
199
199
  /**
200
200
  * 一个实验的覆盖事实:已知 eval 并集(分母)与当前口径下没有任何 attempt 的题。
201
- * `missingEvalIds` 永远被算出来,不静默——渲染面把它转成榜单占位行
201
+ * `missingEvalIds` 永远被算出来,不静默——渲染面把它转成覆盖占位行
202
202
  * (见 docs/feature/sample/library.md「选择快照」「时效:新执行与历史执行」)。
203
203
  */
204
204
  export interface ScopeCoverage {
@@ -112,7 +112,7 @@ export type CommandsArtifact = FailedCommandEvidence[];
112
112
  /**
113
113
  * 使 attempt 无法正常完成的唯一致命执行错误(见 docs/feature/record/architecture.md 的
114
114
  * `AttemptError`)。`message` 是人可读的一层原因(不拼整份 SDK response);完整 stack 单放
115
- * `stack`,`niceeval show @locator` 首页展开、终端即时反馈不整段打印。榜单只显示 `message`。
115
+ * `stack`,`niceeval show @locator` 首页展开、终端即时反馈不整段打印。默认报告只显示 `message`。
116
116
  */
117
117
  export interface AttemptError {
118
118
  /** 稳定、可供 CI/Agent 分支处理的机器码;未知异常使用 `"unexpected-error"`。 */
@@ -183,7 +183,7 @@ export interface EvalResult {
183
183
  scoreEntries?: ScoreEntry[];
184
184
  usage?: Usage;
185
185
  estimatedCostUSD?: number;
186
- /** 使 attempt 进入 `errored` 的唯一致命执行错误(结构化);榜单显示 `error.message` 一层原因。 */
186
+ /** 使 attempt 进入 `errored` 的唯一致命执行错误(结构化);默认报告显示 `error.message` 一层原因。 */
187
187
  error?: AttemptError;
188
188
  /** 本 attempt 的诊断(与 verdict 独立);teardown / cleanup 失败等挂在这里,不改判定。 */
189
189
  diagnostics?: readonly DiagnosticRecord[];
@@ -462,7 +462,7 @@ export interface DiscoveredEval extends EvalDef {
462
462
  * active 行的次要文本(短命状态,agent/ci profile 不逐条输出),`diagnostic` 进运行级永久
463
463
  * 事件流(实验级钩子不属于任何单个 attempt,诊断不落 attempt 的 `result.json`;setup 抛错
464
464
  * 以每条 attempt 的结构化 `error` 落盘,失败仍可回顾)。钩子的起止本身由 runner 直接发布为
465
- * 运行级反馈,不依赖这里的 `progress`(见 docs/feature/experiments/cli.md「实验级钩子的显示」)。
465
+ * 运行级反馈,不依赖这里的 `progress`(见 docs/feature/experiments/cli.md「实验级 Hook 的显示」)。
466
466
  */
467
467
  export interface ExperimentHookContext extends ScopedFeedback {
468
468
  readonly experimentId: string;
@@ -831,7 +831,7 @@ export interface ActiveAttempt {
831
831
  export type ExperimentHookName = "setup" | "teardown";
832
832
  /**
833
833
  * dashboard 当前可见的一个实验级钩子运行级行(见 docs/feature/experiments/cli.md
834
- * 「实验级钩子的显示」)。与 `ActiveAttempt` 分开建模:钩子不属于任何单个 attempt、不占并发位,
834
+ * 「实验级 Hook 的显示」)。与 `ActiveAttempt` 分开建模:钩子不属于任何单个 attempt、不占并发位,
835
835
  * 也不参与 `RunFeedbackState` 的计数不变量——等待 setup 的
836
836
  * attempt 保持 `queued`,这行就是「为什么它们还在排队」的解释。`detail` 来自实验级
837
837
  * `ctx.progress`,后一条覆盖前一条。
@@ -991,7 +991,7 @@ export interface RunFeedbackState {
991
991
  * 这行就是「为什么它们还在排队」的解释。undefined = 当前没有在飞的预检。 */
992
992
  activePrecheck?: ActivePrecheck;
993
993
  /** 在飞的实验级钩子(experimentId → 运行级行状态),由 "experiment-hook" 事件增删、
994
- * "experiment:progress" 更新 detail(见 docs/feature/experiments/cli.md「实验级钩子的显示」)。 */
994
+ * "experiment:progress" 更新 detail(见 docs/feature/experiments/cli.md「实验级 Hook 的显示」)。 */
995
995
  experimentHooks: ReadonlyMap<string, ActiveExperimentHook>;
996
996
  /** 在飞的用例锁等待,按 experimentId 聚合(见 `ActiveLockWait`、docs/feature/experiments/cli.md
997
997
  * 「等待并发 run 的显示」)。由 "lock-wait" 事件增删/累计;没有等待用例的实验不出现在这个 map 里。 */
@@ -1144,7 +1144,7 @@ export type DurableFeedbackEvent = {
1144
1144
  }
1145
1145
  /**
1146
1146
  * 实验级钩子(`ExperimentDef.setup` / 它返回的 teardown)的起止,由 runner 在钩子真正
1147
- * 开始/结束时各发一次(见 docs/feature/experiments/cli.md「实验级钩子的显示」)。`failed`
1147
+ * 开始/结束时各发一次(见 docs/feature/experiments/cli.md「实验级 Hook 的显示」)。`failed`
1148
1148
  * 只标记钩子自身的结局——setup 失败的每条 attempt 仍以 "failure" 事件逐条给出。human TTY
1149
1149
  * 用它维护运行级 active 行(不写 scrollback),append-only profile 起止各追加一行。
1150
1150
  */
@@ -11,7 +11,7 @@ export declare function avg(items: number[]): number;
11
11
  export declare function displayExperimentName(id: string | undefined): string | undefined;
12
12
  /**
13
13
  * 实验 id 的组推导:去掉末段的目录前缀("compare/bub-low" → "compare");
14
- * 无 "/" 的顶层实验不属于任何组,返回 undefined。view 榜单分组与自定义报告
14
+ * 无 "/" 的顶层实验不属于任何组,返回 undefined。view 实验列表分组与自定义报告
15
15
  * 的分组用同一份,两边的「组」永远指同一个东西。
16
16
  */
17
17
  export declare function experimentGroupOf(experimentId: string): string | undefined;
@@ -1,4 +1,4 @@
1
- // report 聚合(report/aggregate.ts)与 view 榜单(view/app/lib/rows.ts)共用的聚合小工具。
1
+ // report 聚合(report/aggregate.ts)与 view 实验列表(view/app/lib/rows.ts)共用的聚合小工具。
2
2
  // 实验标签推导、token/成本求和、verdict 排序各只有一份 —— 否则同一个实验在终端和网页上
3
3
  // 会显示成两个名字 / 两组数。保持环境无关(纯函数,只 type import)。
4
4
  /** 明细行排序:失败最靠前(failed > errored > skipped > passed 的紧急程度)。 */
@@ -27,7 +27,7 @@ export function displayExperimentName(id) {
27
27
  }
28
28
  /**
29
29
  * 实验 id 的组推导:去掉末段的目录前缀("compare/bub-low" → "compare");
30
- * 无 "/" 的顶层实验不属于任何组,返回 undefined。view 榜单分组与自定义报告
30
+ * 无 "/" 的顶层实验不属于任何组,返回 undefined。view 实验列表分组与自定义报告
31
31
  * 的分组用同一份,两边的「组」永远指同一个东西。
32
32
  */
33
33
  export function experimentGroupOf(experimentId) {
@@ -33,7 +33,7 @@ Technical Reference 不等于整页都由生成器拼出来。页面仍可手写
33
33
  - 能力矩阵、选择表和行为约束暂时由手写 Reference 承担;它们必须只描述当前实现,并避免重复已经生成的类型签名。
34
34
  - `reference/` 中没有生成区块的页面不因此成为 API 事实的第二来源。出现代码形状时,优先链接已有生成页;确实缺少生成入口时先补生成器。
35
35
 
36
- 运行 `pnpm docs:reference` 后,生成器只改 `zh/reference/` 中已登记的 region。`test/reference-consistency.test.ts` 会拦截源码与生成区块的漂移。
36
+ 运行 `pnpm docs:reference` 后,生成器只改 `zh/reference/` 中已登记的 region。`test/docs-site/reference-consistency.test.ts` 会拦截源码与生成区块的漂移。
37
37
 
38
38
  ## 当前页面归类
39
39
 
@@ -54,7 +54,14 @@ npx niceeval exp local fixtures/button --runs 5 --early-exit
54
54
 
55
55
  ## 缓存
56
56
 
57
- [NiceEval](https://niceeval.com/) 可以根据输入、配置和相关文件 fingerprint 跳过已判定为 `passed` 或 `failed` 的结果——两者都是判定确定的终态。`errored`(超时、Sandbox 异常等框架/环境层面的不确定失败)永远重试。缓存适合加速迭代,但如果你在调试非确定性行为,应该明确关闭(`--rerun all`)或清理相关缓存。
57
+ [NiceEval](https://niceeval.com/) fingerprint 跳过已判定为 `passed` 或 `failed` 的结果——两者都是判定确定的终态。`errored`(超时、Sandbox 异常等框架/环境层面的不确定失败)永远重试。
58
+
59
+ fingerprint 由两部分组成:
60
+
61
+ - **评估用例的源码**:`.eval.ts` 文件本身,加上它 import 的项目内模块,以及用 `loadYaml` / `loadJson` 读进来的数据文件。断言抽在公共 helper 里时,改那个 helper 会让引用它的评估用例全部重跑。
62
+ - **运行配置**:实验 ID、Agent、model、flags、Sandbox、`Judge` 的模型与端点,以及 `--strict`。超时上限不在里面——它决定等不等得到,不决定跑出来的结果是什么。
63
+
64
+ 被测程序自己的源码、Agent CLI 的版本、Sandbox 镜像的内容都不在 fingerprint 里。改了这些要复验,用 `--rerun`(只重跑失败项)或 `--rerun all`(全部重跑)。调试非确定性行为时同样用 `--rerun all`。
58
65
 
59
66
  ## 并行开多个终端
60
67
 
@@ -109,7 +109,7 @@ npx niceeval exp models weather
109
109
  | `--snapshot` | string | `view` 命令专用:只打开这一份快照文件(`snapshot.json`);文件不可读时命令失败(扫描模式只跳过)。 |
110
110
  | `--report` | string | `show` / `view` 命令专用:用文件默认导出的 `defineReport(...)` 替换两者共用的默认报告。 |
111
111
  | `--page` | string | `show` / `view` 命令专用:选择报告的初始页;`show` 渲染该页并在尾部附其余页索引,`view` 以它作初始路由。未命中的页 id 按用法错误退出并列出可用页 id。 |
112
- | `--fresh` | boolean | `show` / `view` 命令专用:只统计新执行的 attempt(排除携带条目与跨快照拼入的历史执行);被排除的题按覆盖事实转为榜单占位行,不静默消失。 |
112
+ | `--fresh` | boolean | `show` / `view` 命令专用:只统计新执行的 attempt(排除携带条目与跨快照拼入的历史执行);被排除的题按覆盖事实转为覆盖占位行,不静默消失。 |
113
113
  | `--teardown` | boolean | `exp` 命令专用:补齐被强杀打断的实验级 teardown——只对选中的实验各执行一次 teardown(新进程语义),不派发 attempt、不跑 setup;没有遗留登记也照常执行。与 eval 前缀位置参数组合是用法错误。 |
114
114
  | `--dry` | boolean | 只打印本次会匹配到的 eval × 运行配置,不实际执行(人读文本或 `--json` 单文档,见「机器怎么读:--json」)。 |
115
115
  | `--force` | boolean | 忽略上次运行结果,不跳过已通过的 (experiment, eval) 组合,强制全部重跑。 |
@@ -33,7 +33,7 @@ description: "报告文件里能摆的全部官方双面组件:每个组件回
33
33
  - **排序与方向随指标的 `better`。** higher 的指标降序、lower 的升序,「好」的一头恒在上、在右上。
34
34
  - **深链到 Attempt 详情。** 网页面的格子、点和条目深链到 Attempt 详情页;终端面用同一 Attempt 定位符交给 `niceeval show @<id>`。
35
35
  - **终端输出形成反馈闭环。** 每个 Attempt 有一个以 `@` 开头的短定位符,例如 `@1k2m9qrs`。它唯一指向 experiment、结果快照、评估用例和 Attempt。`✓` / `✗` / `!` / `–` 是 passed / failed / errored / skipped。列表不用字母缩写编码证据可用性——定位符本身就是证据入口;打开 attempt(`niceeval show @<定位符>`)后再列出实际可用的证据命令。执行步骤统一包含消息、thinking、tool call/result 和 Skill load;OTel 只给这些步骤补时间,不另开一份输出。
36
- - **两面同口径,网页面不依赖 JS 也完整。** 排序在计算时由 `sort` 定死,终端和网页看到同一份基准顺序;下钻是普通链接,展开折叠用 `<details>`。网页面另有一层浏览操作:点表头就地重排、榜单行过滤、图表点位悬停看数值——只影响眼前的视图,不改数据口径,刷新即回基准顺序;浏览器禁用 JS 时这些操作消失,内容一样不少(悬停信息退化为图内提示)。
36
+ - **两面同口径,网页面不依赖 JS 也完整。** 排序在计算时由 `sort` 定死,终端和网页看到同一份基准顺序;下钻是普通链接,展开折叠用 `<details>`。网页面另有一层浏览操作:点表头就地重排、列表行过滤、图表点位悬停看数值——只影响眼前的视图,不改数据口径,刷新即回基准顺序;浏览器禁用 JS 时这些操作消失,内容一样不少(悬停信息退化为图内提示)。
37
37
 
38
38
  ## 两种写法,同一份数据
39
39
 
@@ -385,9 +385,9 @@ next: niceeval show geometry/area
385
385
 
386
386
  网页面点格子深链到该格的 attempt;终端面在表下印下钻命令。
387
387
 
388
- ## 分组条形图(`BarChart`)
388
+ ## 分组柱状图(`BarChart`)
389
389
 
390
- 同一批数据换成条形:按组并排比大小,回答「每个科目上谁领先、差多少」。横轴一组条、每条数据一根柱、柱高是指标值——benchmark 发布图(Terminal-Bench、BrowseComp 各一组,每个 agent 一根柱)就是这个形状。
390
+ 同一批数据换成柱状:按组并排比大小,回答「每个科目上谁领先、差多少」。横轴一组柱、每条数据一根柱、柱高是指标值——benchmark 发布图(Terminal-Bench、BrowseComp 各一组,每个 agent 一根柱)就是这个形状。
391
391
 
392
392
  ```tsx
393
393
  <BarChart>
@@ -406,11 +406,11 @@ geometry
406
406
  codex —
407
407
  ```
408
408
 
409
- 网页面是竖向分组柱:柱顶要数值就加一个 `<LabelList position="top" />`,颜色与同页其它组件一致,图例自动生成。终端面横向条形,字符宽度即刻度,同组内按值排序(方向随 `better`)。`better: "lower"` 的指标(成本、耗时)条形反向填充,短条恒为「好」。同一页里矩阵和条形图用同一组维度时,底层数据只算一次。
409
+ 网页面是竖向分组柱:柱顶要数值就加一个 `<LabelList position="top" />`,颜色与同页其它组件一致,图例自动生成。终端面横向条形,字符宽度即刻度,同组内按值排序(方向随 `better`)。`better: "lower"` 的指标(成本、耗时)条形反向填充,短条恒为「好」。同一页里矩阵和柱状图用同一组维度时,底层数据只算一次。
410
410
 
411
- ### benchmark 站首屏的那张排行榜
411
+ ### benchmark 站首屏的那张排行柱状图
412
412
 
413
- 换成横向、一行一名、按值排序,就是 benchmark 站首屏那块榜单:
413
+ 换成横向、一行一名、按值排序,就是 benchmark 站首屏那块排行柱状图:
414
414
 
415
415
  ```tsx
416
416
  <BarChart layout="vertical">
@@ -158,13 +158,13 @@ latest.coverage[0];
158
158
  // }
159
159
  ```
160
160
 
161
- 缺口是逐题的事实,所以呈现在题的位置上:`niceeval show` / `view` 的榜单把缺的题渲染成「当前配置下无结果」占位行,旁边就是可复制的补跑命令——你在正在看的表里直接看见分母缺口。程序判断同样直接:CI 里「覆盖缩水就 fail」判 `coverage.some((c) => c.missingEvalIds.length > 0)`,不解析文本。缺口永远被算出来,不静默。
161
+ 缺口是逐题的事实,所以呈现在题的位置上:`niceeval show` / `view` 的默认报告把缺的题渲染成「当前配置下无结果」占位行,旁边就是可复制的补跑命令——你在正在看的表里直接看见分母缺口。程序判断同样直接:CI 里「覆盖缩水就 fail」判 `coverage.some((c) => c.missingEvalIds.length > 0)`,不解析文本。缺口永远被算出来,不静默。
162
162
 
163
163
  `warnings` 收的是定位不到具体某道题的完整性问题:选中的快照没收尾(进程中断)进 `unfinished-snapshot`、落盘读不了进 `unreadable-snapshot`,每种都带 `kind`、可判断的结构化字段和渲染好的英文 `message`(要展示就原样打)。
164
164
 
165
165
  `snap.diagnostics` 和 `warnings` 分工不同:warnings 讲的是「这批数据是怎么挑出来的」,`diagnostics` 讲的是「某一次实验跑的时候出了什么事」——实验级 teardown 失败、预算没法执行这类记录,落不到某道题上,就跟着它真正所属的那次结果快照一起收尾写盘。它们始终绑定自己的 `experimentId` 和 `startedAt`,不会被合并成整个 Scope 的结论,也不会复制到每条 attempt 上;展示用快照诊断(`SnapshotDiagnostics`)组件,逐条保留是哪一次跑出来的、多久以前跑的。
166
166
 
167
- 每条结果还带**时效**:携带条目(缓存命中、上一轮的结果合入本快照)`attempt.carried` 为 true,榜单在这类行后标 `↩` 加时距(如 `↩ 3d`)——旧但有效,fingerprint 担保过没改,所以是行内标注不是警告。只想看最新一次真实跑出来的结果,用 `results.latest({ fresh: true })` 或 CLI 的 `--fresh`,被排除的题会转成占位行,不会静默消失。
167
+ 每条结果还带**时效**:携带条目(缓存命中、上一轮的结果合入本快照)`attempt.carried` 为 true,默认报告在这类行后标 `↩` 加时距(如 `↩ 3d`)——旧但有效,fingerprint 担保过没改,所以是行内标注不是警告。只想看最新一次真实跑出来的结果,用 `results.latest({ fresh: true })` 或 CLI 的 `--fresh`,被排除的题会转成占位行,不会静默消失。
168
168
 
169
169
  Scope 是[报告积木](/zh/tutorials/custom-reports)和下文 `copySnapshots` 的通用输入:收 `Scope` 时 coverage 与 warnings 随行(占位行与 `ScopeWarnings` 组件会如实展示),手工挑的 `Snapshot[]` 数组照收。`scope.snapshots` 里的每一项都是盘上那份真实结果快照,`diagnostics` 跟着它走,所以两种输入都能渲染快照诊断。微调官方口径不用降级成裸数组:`latest.filter((s) => s.experimentId !== "compare/broken")` 返回新 Scope——快照被删减,coverage 与 warnings 修剪到幸存的实验,provenance 不丢。`filter` 只做删减;「换成该实验上一个完整快照」这类**替换式**重挑不是它的事,回到 `exp.snapshots` 自己拿——手工挑的数组没有挑选过程,自然没有覆盖事实可带,也如实。
170
170
 
@@ -229,7 +229,7 @@ for (const r of convertedResults) {
229
229
  await writer.finish(); // 给每个快照补 completedAt,没有任何收尾聚合
230
230
  ```
231
231
 
232
- `writer.snapshot()` 就是读取面「实验 → 快照」层次的镜像:转多个 experiment 就开多个快照目录,experimentId / agent / model / startedAt 这些快照级元数据在这里声明一次,不用塞进每条 attempt;可选的 `knownEvalIds`(该实验已知的评估用例并集)也在这里声明——它是残缺检测的分母,转换只覆盖部分题目时如实交代全集,下游的覆盖缺口(`coverage` 与榜单占位行)就能算出来(`copySnapshots` 发布时会自动补记这个字段,见下文)。转完的目录就是标准结果目录:`niceeval show` / `niceeval view` 直接能看,报告积木直接能算,不用抄格式文档;`producer` 会原样出现在读取面的 `snap.producer` 上。**每个文件恰好写入一次**是写入面的核心承诺:`snapshot.json` 开跑即写、收尾只补 `completedAt`;`result.json` 与 artifact 随 attempt 完成落盘。进程中断只丢未完成的 attempt,已完成的判定与 artifact 已经在盘上——真正「有 attempt 落盘却没有 `snapshot.json`」的极端情况才归 `skipped("incomplete")`,未收尾但元数据齐全的快照能正常读,只带一条警告。
232
+ `writer.snapshot()` 就是读取面「实验 → 快照」层次的镜像:转多个 experiment 就开多个快照目录,experimentId / agent / model / startedAt 这些快照级元数据在这里声明一次,不用塞进每条 attempt;可选的 `knownEvalIds`(该实验已知的评估用例并集)也在这里声明——它是残缺检测的分母,转换只覆盖部分题目时如实交代全集,下游的覆盖缺口(`coverage` 与覆盖占位行)就能算出来(`copySnapshots` 发布时会自动补记这个字段,见下文)。转完的目录就是标准结果目录:`niceeval show` / `niceeval view` 直接能看,报告积木直接能算,不用抄格式文档;`producer` 会原样出现在读取面的 `snap.producer` 上。**每个文件恰好写入一次**是写入面的核心承诺:`snapshot.json` 开跑即写、收尾只补 `completedAt`;`result.json` 与 artifact 随 attempt 完成落盘。进程中断只丢未完成的 attempt,已完成的判定与 artifact 已经在盘上——真正「有 attempt 落盘却没有 `snapshot.json`」的极端情况才归 `skipped("incomplete")`,未收尾但元数据齐全的快照能正常读,只带一条警告。
233
233
 
234
234
  ## 发布:`copySnapshots`
235
235
 
@@ -279,7 +279,12 @@ Coding Agent 应从 `failure` / `error` 事件里取出 `locator`,再逐个运
279
279
 
280
280
  ## 结果复用条件
281
281
 
282
- 不传 `--rerun all` 时,NiceEval 会比较当前指纹与最近结果。指纹由评估用例源码和运行配置组成,包括实验 ID、Agent、model、flags、Sandbox、timeout 与 strict 等设置。
282
+ 不传 `--rerun all` 时,NiceEval 会比较当前指纹与最近结果。指纹由两部分组成:
283
+
284
+ - **评估用例的源码**:`.eval.ts` 文件本身,加上它 import 的项目内模块,以及用 `loadYaml` / `loadJson` 读进来的数据文件。
285
+ - **运行配置**:实验 ID、Agent、model、flags、Sandbox、`Judge` 的模型与端点,以及 `--strict`。
286
+
287
+ 超时上限不在指纹里:它决定等不等得到,不决定跑出来的结果是什么。改大改小都不会作废已完成的结果。
283
288
 
284
289
  | 最近结果与当前输入 | 本次行为 |
285
290
  | --- | --- |
@@ -292,7 +297,7 @@ Coding Agent 应从 `failure` / `error` 事件里取出 `locator`,再逐个运
292
297
  被测程序的源码不在指纹里。修改实现后,即使行为已经变化,旧的 `passed` 或 `failed` 仍可能被复用。因此可以这样选择:
293
298
 
294
299
  - 只想重看已有结果:运行 `niceeval show`,不产生新费用。
295
- - 修改了评估用例或实验配置:直接重跑;指纹变化会触发对应任务。
300
+ - 修改了评估用例或实验配置:直接重跑;指纹变化会触发对应任务。改公共 helper、改数据文件、换 `Judge` 模型都算在内。
296
301
  - 修改了被测程序,要复验失败项:加 `--rerun`。已通过的照常携入,不必先去找失败的评估用例 ID——失败面板的 `Retry:` 行给的就是这条命令。
297
302
  - 准备结束本轮工作:对整个实验使用 `--rerun all`,排除其它评估用例的回归。
298
303
 
@@ -101,7 +101,7 @@ const ProdSummary = defineComponent((_props: {}, ctx) => (
101
101
 
102
102
  快照诊断(`SnapshotDiagnostics`)组件挨着选择警告摆,显示的是另一类事情:某一次实验跑的时候出了问题、但落不到具体某道题上,比如实验级 teardown 失败或者预算没法执行。它按实验和结果快照分组,每条保留是哪一次跑出来的、多久以前跑的、严重程度、原文和可复制的下一步命令。网页面整块默认折起,`<summary>` 那行恒定可见,一眼能看到涉及几次运行、共几条、最高严重到什么程度;终端面不折叠,顺序打完。这批数据为空时组件不输出任何东西。默认报告的每一页也都包含它;自定义报告需要显示时,在 `<ScopeWarnings />` 旁边加 `<SnapshotDiagnostics />`。
103
103
 
104
- 页面里的每个组件都是**双面**的:网页面是 React 渲染,终端面是字符渲染,两面吃同一份算好的数据。实体列表按 experiment → Eval → Attempt 展示事实;指标表、矩阵、条形图、成绩单、散点图、趋势图和差异表展示聚合值。完整清单见[报告组件](/zh/reference/report-components)。网页面的实体、格子和点深链到 Attempt 详情,终端面印出对应的 `niceeval show <eval id>` 下钻命令。
104
+ 页面里的每个组件都是**双面**的:网页面是 React 渲染,终端面是字符渲染,两面吃同一份算好的数据。实体列表按 experiment → Eval → Attempt 展示事实;指标表、矩阵、柱状图、成绩单、散点图、趋势图和差异表展示聚合值。完整清单见[报告组件](/zh/reference/report-components)。网页面的实体、格子和点深链到 Attempt 详情,终端面印出对应的 `niceeval show <eval id>` 下钻命令。
105
105
 
106
106
  默认报告没有特权:它的四个页面全部由公开组件搭成。需要同样的当前 Scope 比较就写 `<ExperimentComparison />`;要子集就在报告里先 `filter`,或从 CLI 用 `--exp` 收窄。
107
107
 
@@ -326,7 +326,7 @@ export default defineReport(
326
326
 
327
327
  ## 换形态:表格用 Table,摘要卡片用 Grid/Stat,其余自己画
328
328
 
329
- 内置组件未覆盖的展示分三类:表格使用排版原语 `<Table>`;label-value 的自由摘要卡片使用 `<Grid>` / `<Stat>`;通过率条形图、预算燃尽图和项目徽章这类真正需要自己画的展示,才用 `defineComponent` 编写双面组件。
329
+ 内置组件未覆盖的展示分三类:表格使用排版原语 `<Table>`;label-value 的自由摘要卡片使用 `<Grid>` / `<Stat>`;通过率柱状图、预算燃尽图和项目徽章这类真正需要自己画的展示,才用 `defineComponent` 编写双面组件。
330
330
 
331
331
  ### 一张表:`<Table>`
332
332
 
@@ -486,7 +486,7 @@ codex ████████████████░░░░ 80%
486
486
 
487
487
  ### 让自己的组件和官方组件叫同一个名字、上同一个颜色
488
488
 
489
- 同一页里,`compare/with-memory` 在官方榜单上缩成 `with-memory`、配一个蓝色;自己写的组件要显示成同一个样子,用这两个出口,不要自己实现一遍:
489
+ 同一页里,`compare/with-memory` 在官方默认报告上缩成 `with-memory`、配一个蓝色;自己写的组件要显示成同一个样子,用这两个出口,不要自己实现一遍:
490
490
 
491
491
  ```tsx
492
492
  import { defineComponent, experimentListData, shortestUniqueLabels } from "niceeval/report";
@@ -62,7 +62,7 @@ t.check(t.reply, includes("friendly tone").atLeast(0.7));
62
62
 
63
63
  ## 计分制:检查点没走完也要看走了几步
64
64
 
65
- `defineEval` 把一次运行折成一个"过"或"不过"。有些任务分步骤,走完三步比一步没走强得多——这类任务用 `defineScoreEval`,题内用给分 API 累加挣分,`niceeval show` / `view` 的榜单读总分而不是通过率:
65
+ `defineEval` 把一次运行折成一个"过"或"不过"。有些任务分步骤,走完三步比一步没走强得多——这类任务用 `defineScoreEval`,题内用给分 API 累加挣分,`niceeval show` / `view` 的默认报告读总分而不是通过率:
66
66
 
67
67
  ```ts
68
68
  import { defineScoreEval } from "niceeval";
@@ -53,7 +53,7 @@ description: "用 niceeval show 在终端按 @<locator> 查看 Attempt 的评估
53
53
  ```bash
54
54
  niceeval show # 默认报告:比较当前 Scope 并下钻到 Attempt
55
55
  niceeval show weather # 前缀过滤:weather/* 下每个 eval 的判定
56
- niceeval show weather/brooklyn # 收窄到一个 eval:同一份榜单,只保留它的 experiment × Attempt 展开
56
+ niceeval show weather/brooklyn # 收窄到一个 eval:同一份默认报告,只保留它的 experiment × Attempt 展开
57
57
  niceeval show @1k2m9qrs # 精确到一次 Attempt:断言、执行、diff 与可用证据摘要
58
58
  niceeval show @1k2m9qrs --source # 该 Attempt 运行时保存的 Eval 源码,断言标回源码行
59
59
  niceeval show @1k2m9qrs --execution # 该 Attempt 的消息、thinking、Skill 加载、工具调用,有 OTel 时补时间
@@ -77,7 +77,7 @@ Sandbox 创建、setup 或 teardown 错误不依赖 trace。`result.json` 保存
77
77
  | `niceeval view` 里的视图 | 终端对应 |
78
78
  | --- | --- |
79
79
  | 当前结果的分组比较报告 | `niceeval show` |
80
- | 收窄到该 eval 前缀的榜单:各 experiment × Attempt 的判定与摘要 | `niceeval show <eval id>` |
80
+ | 收窄到该 eval 前缀的默认报告:各 experiment × Attempt 的判定与摘要 | `niceeval show <eval id>` |
81
81
  | 单次 Attempt 摘要(断言、执行、diff 与证据可用性) | `niceeval show @<locator>` |
82
82
  | 评估用例源码标注(断言标回源码行) | `niceeval show @<locator> --source` |
83
83
  | AI 对话、thinking、Skill 加载与工具调用(有 OTel 时补时间) | `niceeval show @<locator> --execution` |
@@ -91,9 +91,9 @@ Sandbox 创建、setup 或 teardown 错误不依赖 trace。`result.json` 保存
91
91
 
92
92
  实验列表先给固定列汇总,再按 experiment → 评估用例 → Attempt 展开。locator 只保留 `@<id>`;完整断言和 evidence 留在 `niceeval show @<locator>`。只有一个 experiment 时散点仍显示单点。
93
93
 
94
- ### 用 eval 前缀收窄榜单
94
+ ### 用 eval 前缀收窄默认报告
95
95
 
96
- eval id 前缀不是另一套视图——它只是把当前 Scope 收窄到匹配的评估用例,渲染的仍是和裸 `niceeval show` 同一份默认榜单:散点图、固定列汇总,再按 experiment → 评估用例 → Attempt 展开,只是这里的评估用例只剩下匹配前缀的那些。同一个评估用例的多次 Attempt 全部按顺序逐条列出,不做「默认展开某一次」的取舍:
96
+ eval id 前缀不是另一套视图——它只是把当前 Scope 收窄到匹配的评估用例,渲染的仍是和裸 `niceeval show` 同一份默认报告:散点图、固定列汇总,再按 experiment → 评估用例 → Attempt 展开,只是这里的评估用例只剩下匹配前缀的那些。同一个评估用例的多次 Attempt 全部按顺序逐条列出,不做「默认展开某一次」的取舍:
97
97
 
98
98
  ```text
99
99
  $ niceeval show weather/brooklyn
@@ -670,11 +670,11 @@ Soft 断言的分数记录在 `assertions[].score` 里;非 `--strict` 模式
670
670
 
671
671
  ## 调试建议
672
672
 
673
- - 榜单里失败/错误的题每条自带下钻命令:`niceeval show <eval id>` 先看断言明细,行尾的 `@<locator>` 可以直接精确下钻到某一次 Attempt。
673
+ - 默认报告里失败/错误的题每条自带下钻命令:`niceeval show <eval id>` 先看断言明细,行尾的 `@<locator>` 可以直接精确下钻到某一次 Attempt。
674
674
  - 检查评估用例内容和断言结果时使用 `--source`,断言标注会对应到源码行。
675
675
  - 检查 Agent 消息和调用时使用 `--execution`;关联成功的 OTel 时间会显示在同一事件旁。
676
676
  - coding-agent 失败时看 `--diff` 和 `--execution` 里的工具调用;两者结合能看出「改错了文件」还是「压根没调用该调用的工具」。
677
677
  - Sandbox 评估用例运行缓慢或超时时,先看 `--timing`。该视图分别列出排队、Sandbox 启动、setup hook 中的 shell、Agent 安装命令、每轮 `send`、可关联的 OTel model/tool 以及收尾阶段耗时。
678
- - 同批题在多个条件下跑过时,用多个 `--exp` 看逐题对照矩阵,不要只盯着两次单条件榜单肉眼对比。
678
+ - 同批题在多个条件下跑过时,用多个 `--exp` 看逐题对照矩阵,不要只盯着两次单条件的默认报告肉眼对比。
679
679
  - 怀疑某道题本身有问题(不是这次条件变化导致)时,先看 `--stats` 里它是不是在所有条件、所有历史执行里都 `never passed`。
680
680
  - 定位被测程序或评估用例缺陷并完成重跑的流程见 [Coding Agent 反馈闭环](/zh/tutorials/agent-feedback-loop)。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "niceeval",
3
- "version": "0.11.3",
3
+ "version": "0.11.4-canary.12",
4
4
  "description": "Agent-native eval tool — eval agents, services, functions, and coding-agent fixtures",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -169,8 +169,10 @@
169
169
  },
170
170
  "scripts": {
171
171
  "typecheck": "tsc --noEmit",
172
- "test": "vitest run",
173
- "test:watch": "vitest",
172
+ "test": "vitest run --project unit",
173
+ "test:watch": "vitest --project unit",
174
+ "test:docs": "vitest run --project docs",
175
+ "test:docs-site": "vitest run --project docs-site && pnpm run docs:validate && pnpm run docs:links",
174
176
  "niceeval": "node bin/niceeval.js",
175
177
  "e2e": "tsx e2e/scripts/run.ts",
176
178
  "gen:diff-code": "tsx scripts/gen-diff-code.ts",
@@ -154,7 +154,7 @@ function firstJsonField(raw: string | undefined, field: string): string | undefi
154
154
  * 否则 transcript 为空时失败原因彻底丢失,用户只能干瞪眼。
155
155
  *
156
156
  * 分层:首行是一层可行动摘要(exit code · transcript 状态 · 最后一条 error 的首行),
157
- * output tail 从第二行起按原始换行保留——scrollback 失败行 / 榜单等单行面对 message 取
157
+ * output tail 从第二行起按原始换行保留——scrollback 失败行 / 默认报告等单行面对 message 取
158
158
  * 首行即得一层摘要,tail 归 `show` 的 attempt 详情展开(docs/feature/experiments/cli.md
159
159
  * 「运行反馈」:执行错误即时输出一层摘要,不把 stack 或 SDK 输出灌进 scrollback)。
160
160
  * lastErr 的完整多行文本已是 events 里的独立事件,首行截取不丢证据。
package/src/cli.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  // niceeval CLI 入口。执行 eval 必须以 experiment 为单位;位置参数只在 exp 后筛 eval id 前缀。
2
2
  // niceeval exp [组|配置] [pattern] 跑实验
3
- // niceeval show [pattern] 终端读结果:榜单 / 单 eval / 证据切面 / 时间轴 / --report
3
+ // niceeval show [pattern] 终端读结果:默认报告 / 单 eval / 证据切面 / 时间轴 / --report
4
4
  // niceeval list 只列出发现到的 eval
5
5
  // niceeval clean 删除 .niceeval/ 历史运行 artifact
6
6
 
@@ -205,7 +205,7 @@ const FLAG_OPTIONS = {
205
205
  report: { type: "string" },
206
206
  /** `show` / `view` 命令专用:选择报告的初始页;`show` 渲染该页并在尾部附其余页索引,`view` 以它作初始路由。未命中的页 id 按用法错误退出并列出可用页 id。 */
207
207
  page: { type: "string" },
208
- /** `show` / `view` 命令专用:只统计新执行的 attempt(排除携带条目与跨快照拼入的历史执行);被排除的题按覆盖事实转为榜单占位行,不静默消失。 */
208
+ /** `show` / `view` 命令专用:只统计新执行的 attempt(排除携带条目与跨快照拼入的历史执行);被排除的题按覆盖事实转为覆盖占位行,不静默消失。 */
209
209
  fresh: { type: "boolean" },
210
210
  /** `exp` 命令专用:补齐被强杀打断的实验级 teardown——只对选中的实验各执行一次 teardown(新进程语义),不派发 attempt、不跑 setup;没有遗留登记也照常执行。与 eval 前缀位置参数组合是用法错误。 */
211
211
  teardown: { type: "boolean" },
@@ -213,7 +213,7 @@ export function createEvalContext(deps: ContextDeps): { context: TestContext; st
213
213
  /** 断言失败时给 view 看的「实际被检查了什么」,而不是重复 matcher 自己的名字。
214
214
  * 按值的形状落成人可读事实(而不是留一坨 JSON 给渲染层解析):CommandResult 的第一行是
215
215
  * `exit N · "…输出尾部摘要"`(stdout+stderr 合并折单行,信号常收在末尾——pytest / vitest
216
- * 的 failed 计数都在最后几行;榜单与 --eval 标注这类单行面只保留这一行),随后附原样保留
216
+ * 的 failed 计数都在最后几行;默认报告与 --eval 标注这类单行面只保留这一行),随后附原样保留
217
217
  * 换行的更长尾部——runner 不另存 eval 侧命令的输出,这条记录就是它唯一的家,attempt 首页
218
218
  * 与 result.json 靠它给出「更进一步」;文件引用带 `// path` 头;其余走通用 JSON 预览。 */
219
219
  function previewCheckedValue(value: unknown): string {
package/src/i18n/zh-CN.ts CHANGED
@@ -92,7 +92,7 @@ export const zhCN = {
92
92
  " --teardown 强杀后补收尾:只对选中的实验各执行一次 teardown(不派发\n" +
93
93
  " attempt、不跑 setup);与 eval id 前缀组合是用法错误\n" +
94
94
  " niceeval show [eval-id 前缀… | @<locator>] 终端读结果\n" +
95
- " 不带证据 flag:命中范围的榜单(裸跑、eval id 前缀、单个 --exp 都落在这里);\n" +
95
+ " 不带证据 flag:命中范围的默认报告(裸跑、eval id 前缀、单个 --exp 都落在这里);\n" +
96
96
  " 两个以上 --exp 改为逐条件对照\n" +
97
97
  " @<locator> 精确一个 attempt:无 flag → 紧凑全景;带 flag → 对应证据切面\n" +
98
98
  " --source 该 attempt 运行时保存的 Eval 源码,断言标回源码行\n" +
@@ -671,7 +671,7 @@ describe("实体列表 data", () => {
671
671
  expect(items[0]!.evalRows.map((row) => row.evalId)).toEqual(["a", "b"]); // 占位行不在 evalRows 里(占位行只在渲染面合成)
672
672
  });
673
673
 
674
- it("coverage-only 实验也产生榜单占位行;--fresh 清空全部 attempt 时缺口不再静默消失", async () => {
674
+ it("coverage-only 实验也产生覆盖占位行;--fresh 清空全部 attempt 时缺口不再静默消失", async () => {
675
675
  const scope = scopeOf([], [], [{ experimentId: "exp/fresh", knownEvalIds: ["a", "b"], missingEvalIds: ["a", "b"] }]);
676
676
  const items = await experimentListData(scope);
677
677
  expect(items).toHaveLength(1);
@@ -1,4 +1,4 @@
1
- // MetricBars:分组条形——同一份矩阵数据的另一种摆法(MetricBars.data = MetricMatrix.data)。
1
+ // MetricBars:分组柱状——同一份矩阵数据的另一种摆法(MetricBars.data = MetricMatrix.data)。
2
2
  // 组维度一组条、系列维度一根条、条长是指标值;竖向分组柱,柱顶标数值,系列颜色与
3
3
  // 其它组件的稳定配色一致(类名 nre-series-cN 由 CSS 上色,深色主题跟随),图例自动生成。
4
4
  // 组内按值排序,方向随 better;缺数据的系列不画柱、不编 0(与 text 面的 — 同口径)。
@@ -603,7 +603,7 @@ async function buildDeltaCell(items: readonly Item[]): Promise<DeltaCell> {
603
603
  return {
604
604
  scoring,
605
605
  verdict,
606
- // totalScore 是题目级挣分(各 attempt 均值,与榜单 totalScore 指标同一套 perEval 聚合);
606
+ // totalScore 是题目级挣分(各 attempt 均值,与默认报告 totalScore 指标同一套 perEval 聚合);
607
607
  // totalTokens / totalCostUSD 是该题在该条件下全部 attempt 的合计,不是均值。
608
608
  ...(scoreCount > 0 ? { totalScore: scoreSum / scoreCount } : {}),
609
609
  attempts: [...refs].sort(),
@@ -1,7 +1,7 @@
1
1
  // cases: docs/engineering/testing/unit/reports.md
2
2
  // 「show 的范围 × 切片正交」deltaTableData 判据段。
3
3
  // deltaTableData(对照矩阵):配对身份是 eval id、翻转标记的数据面、逐行 Δ 为原始差值且缺失不为
4
- // 0、runs>1 的格内折叠(verdict 榜单口径、tokens/成本合计)、totals 与 pairedDelta 两个不同分母
4
+ // 0、runs>1 的格内折叠(verdict 按默认报告口径、tokens/成本合计)、totals 与 pairedDelta 两个不同分母
5
5
  // 的口径(fixture 让两侧覆盖不同,抓出直接相减各自 totals 的错误算法)、混型分段、conditionsByFlag
6
6
  // 派生(单一可比性桶、0 候选空态、by 非 experiment 报错)。show/compare.md 示例数字复算作 fixture。
7
7
 
@@ -109,7 +109,7 @@ describe("deltaTableData", () => {
109
109
  expect(data.rows.find((r) => r.key === "condOnly")!.delta).toBeUndefined();
110
110
  });
111
111
 
112
- it("runs>1 的格内折叠:verdict 按榜单口径(任一轮通过则通过),tokens/成本按全部 attempt 合计不是均值", async () => {
112
+ it("runs>1 的格内折叠:verdict 按默认报告口径(任一轮通过则通过),tokens/成本按全部 attempt 合计不是均值", async () => {
113
113
  const base = snap("exp/base", [
114
114
  res("retry", "failed", { attempt: 0, usage: usage(300, 0.4) }),
115
115
  res("retry", "passed", { attempt: 1, usage: usage(344, 0.47) }),
@@ -300,7 +300,7 @@ export type MetricTableProps = DataProps<
300
300
  }
301
301
  >;
302
302
 
303
- /** 榜单:一行一个维度值、一列一个指标,回答「谁整体更好」。 */
303
+ /** 指标表:一行一个维度值、一列一个指标,回答「谁整体更好」。 */
304
304
  export const MetricTable = makeDataComponent<
305
305
  TableData,
306
306
  MetricTableOptions,
@@ -349,7 +349,7 @@ export const MetricMatrix = makeDataComponent<
349
349
  text: (props, ctx) => matrixText(props.data, ctx),
350
350
  }) as unknown as ReportComponent<MetricMatrixProps>;
351
351
 
352
- /** 分组条形:同一份矩阵数据的另一种摆法;与 MetricMatrix 写同一份 spec 时只计算一次。 */
352
+ /** 分组柱状:同一份矩阵数据的另一种摆法;与 MetricMatrix 写同一份 spec 时只计算一次。 */
353
353
  export const MetricBars = makeDataComponent<
354
354
  MatrixData,
355
355
  MetricMatrixOptions,
@@ -262,7 +262,7 @@ export interface ScoreboardData {
262
262
  }
263
263
 
264
264
  /**
265
- * `DeltaTable` 的一格:同一条件值 × eval 的折叠(docs/feature/reports/components/tables/delta-table.md)。`verdict` / `totalScore` 用与榜单同一套题目级判定口径(`totalScore` 取各
265
+ * `DeltaTable` 的一格:同一条件值 × eval 的折叠(docs/feature/reports/components/tables/delta-table.md)。`verdict` / `totalScore` 用与默认报告同一套题目级判定口径(`totalScore` 取各
266
266
  * attempt 的均值);`totalTokens` / `totalCostUSD` 是该题在该条件下全部 attempt 的**合计**,
267
267
  * 不是均值。
268
268
  */
@@ -375,7 +375,7 @@ describe("时效:carried 投影与 fresh 口径", () => {
375
375
  expect(fresh.attempts).toEqual([]);
376
376
  const coverage = fresh.coverage.find((c) => c.experimentId === "e")!;
377
377
  expect(coverage.missingEvalIds).toEqual(["q1"]);
378
- // coverage-only 实验(零 snapshot 贡献)经 filter 后覆盖缺口不静默消失——榜单占位行的上游事实。
378
+ // coverage-only 实验(零 snapshot 贡献)经 filter 后覆盖缺口不静默消失——覆盖占位行的上游事实。
379
379
  expect(fresh.filter(() => true).coverage).toEqual(fresh.coverage);
380
380
  });
381
381
  });
@@ -211,7 +211,7 @@ export interface Results {
211
211
 
212
212
  /**
213
213
  * 一个实验的覆盖事实:已知 eval 并集(分母)与当前口径下没有任何 attempt 的题。
214
- * `missingEvalIds` 永远被算出来,不静默——渲染面把它转成榜单占位行
214
+ * `missingEvalIds` 永远被算出来,不静默——渲染面把它转成覆盖占位行
215
215
  * (见 docs/feature/sample/library.md「选择快照」「时效:新执行与历史执行」)。
216
216
  */
217
217
  export interface ScopeCoverage {
@@ -125,7 +125,7 @@ export function renderDurableLines(
125
125
  return [];
126
126
  case "experiment-hook": {
127
127
  // 只服务非 TTY 退化流(TTY dashboard 的 appendDurable 对这个事件直接返回,运行级行
128
- // 由 state.experimentHooks 驱动,成功钩子不进 scrollback,见 cli.md「实验级钩子的显示」)。
128
+ // 由 state.experimentHooks 驱动,成功钩子不进 scrollback,见 cli.md「实验级 Hook 的显示」)。
129
129
  const label = experimentHookLabel(event.hook);
130
130
  const duration = event.durationMs !== undefined ? ` (${formatElapsed(event.durationMs)})` : "";
131
131
  const recoverySuffix = event.recovery ? ` (recovery)` : "";
@@ -558,7 +558,7 @@ function createDashboardRenderer(io: FeedbackIO, command: string): FeedbackRende
558
558
  const contentWidth = panelContentWidth(capability.width, capability.mode, false);
559
559
  const rows: PanelRow[] = [{ kind: "line", text: countsText(state) }];
560
560
  // 运行级行(judge 预检 + 实验钩子 + 用例锁等待)排在 attempt 行前面(见 cli.md「judge 预检
561
- // 的显示」/「实验级钩子的显示」/「等待并发 run 的显示」):它们解释了为什么后面的 attempt
561
+ // 的显示」/「实验级 Hook 的显示」/「等待并发 run 的显示」):它们解释了为什么后面的 attempt
562
562
  // 还停在 queued。预检排最前(发生在任何 attempt 派发之前),其次实验钩子,再是锁等待
563
563
  // (排在实验钩子行之后、attempt 行之前)。Map 按插入序迭代,天然满足稳定 slot。
564
564
  const precheck = state.activePrecheck;
@@ -659,7 +659,7 @@ function createDashboardRenderer(io: FeedbackIO, command: string): FeedbackRende
659
659
  appendDurable(event, state) {
660
660
  // 实验级钩子起止在 TTY 下只驱动运行级 active 行(state.experimentHooks 已由 reducer
661
661
  // 更新,coordinator 紧接着的 redrawDynamic 会画出来);成功钩子不写 scrollback 永久行
662
- // (见 cli.md「实验级钩子的显示」)。非 TTY 退化流才逐行追加(见 renderDurableLines)。
662
+ // (见 cli.md「实验级 Hook 的显示」)。非 TTY 退化流才逐行追加(见 renderDurableLines)。
663
663
  // judge 预检同理:TTY 下只驱动 state.activePrecheck 的运行级 active 行(coordinator 紧接着的
664
664
  // redrawDynamic 会画出来),不写 scrollback 永久行(见 cli.md「judge 预检的显示」)。用例锁
665
665
  // 等待同理:TTY 下由 state.lockWaits 驱动运行级 active 行(见 cli.md「等待并发 run 的显示」)。
@@ -164,7 +164,7 @@ export function reduceRunFeedback(state: RunFeedbackState, event: RunFeedbackEve
164
164
  }
165
165
 
166
166
  case "experiment-hook": {
167
- // 运行级行的增删:started 添加,done/failed 移除(见 cli.md「实验级钩子的显示」)。
167
+ // 运行级行的增删:started 添加,done/failed 移除(见 cli.md「实验级 Hook 的显示」)。
168
168
  // 不动 running/queued 计数——等待 setup 的 attempt 保持 queued,计数不变量不受钩子影响。
169
169
  const experimentHooks = new Map(state.experimentHooks);
170
170
  if (event.status === "started") {
package/src/runner/run.ts CHANGED
@@ -566,7 +566,7 @@ export async function runEvals(opts: RunOptions): Promise<InvocationSummary> {
566
566
  // 与 setup 串行:setup 仍在飞(极端时序:全部 attempt 在 setup 完成前被中断收尾)时等它
567
567
  // settle 再收尾;setupPromise 自带 catch(失败收进 setupFailed),这里不会 reject。
568
568
  await lc.setupPromise;
569
- // 起止由 runner 发布,不依赖钩子自己调 progress(见 cli.md「实验级钩子的显示」)。
569
+ // 起止由 runner 发布,不依赖钩子自己调 progress(见 cli.md「实验级 Hook 的显示」)。
570
570
  reportExperimentHook({ experimentId, hook: "teardown", status: "started" });
571
571
  const startedAt = Date.now();
572
572
  try {
@@ -736,7 +736,7 @@ export async function runEvals(opts: RunOptions): Promise<InvocationSummary> {
736
736
  });
737
737
  }
738
738
  if (!run.setup) return;
739
- // 起止由 runner 发布(见 cli.md「实验级钩子的显示」):一个什么都不调的 setup 也必须
739
+ // 起止由 runner 发布(见 cli.md「实验级 Hook 的显示」):一个什么都不调的 setup 也必须
740
740
  // 可见,不能让「0 running · N queued 长时间不动」看起来像调度卡死。
741
741
  reportExperimentHook({ experimentId, hook: "setup", status: "started" });
742
742
  const startedAt = Date.now();
@@ -158,7 +158,7 @@ export type CommandsArtifact = FailedCommandEvidence[];
158
158
  /**
159
159
  * 使 attempt 无法正常完成的唯一致命执行错误(见 docs/feature/record/architecture.md 的
160
160
  * `AttemptError`)。`message` 是人可读的一层原因(不拼整份 SDK response);完整 stack 单放
161
- * `stack`,`niceeval show @locator` 首页展开、终端即时反馈不整段打印。榜单只显示 `message`。
161
+ * `stack`,`niceeval show @locator` 首页展开、终端即时反馈不整段打印。默认报告只显示 `message`。
162
162
  */
163
163
  export interface AttemptError {
164
164
  /** 稳定、可供 CI/Agent 分支处理的机器码;未知异常使用 `"unexpected-error"`。 */
@@ -227,7 +227,7 @@ export interface EvalResult {
227
227
  scoreEntries?: ScoreEntry[];
228
228
  usage?: Usage;
229
229
  estimatedCostUSD?: number;
230
- /** 使 attempt 进入 `errored` 的唯一致命执行错误(结构化);榜单显示 `error.message` 一层原因。 */
230
+ /** 使 attempt 进入 `errored` 的唯一致命执行错误(结构化);默认报告显示 `error.message` 一层原因。 */
231
231
  error?: AttemptError;
232
232
  /** 本 attempt 的诊断(与 verdict 独立);teardown / cleanup 失败等挂在这里,不改判定。 */
233
233
  diagnostics?: readonly DiagnosticRecord[];
@@ -486,7 +486,7 @@ export interface DiscoveredEval extends EvalDef {
486
486
  * active 行的次要文本(短命状态,agent/ci profile 不逐条输出),`diagnostic` 进运行级永久
487
487
  * 事件流(实验级钩子不属于任何单个 attempt,诊断不落 attempt 的 `result.json`;setup 抛错
488
488
  * 以每条 attempt 的结构化 `error` 落盘,失败仍可回顾)。钩子的起止本身由 runner 直接发布为
489
- * 运行级反馈,不依赖这里的 `progress`(见 docs/feature/experiments/cli.md「实验级钩子的显示」)。
489
+ * 运行级反馈,不依赖这里的 `progress`(见 docs/feature/experiments/cli.md「实验级 Hook 的显示」)。
490
490
  */
491
491
  export interface ExperimentHookContext extends ScopedFeedback {
492
492
  readonly experimentId: string;
@@ -880,7 +880,7 @@ export type ExperimentHookName = "setup" | "teardown";
880
880
 
881
881
  /**
882
882
  * dashboard 当前可见的一个实验级钩子运行级行(见 docs/feature/experiments/cli.md
883
- * 「实验级钩子的显示」)。与 `ActiveAttempt` 分开建模:钩子不属于任何单个 attempt、不占并发位,
883
+ * 「实验级 Hook 的显示」)。与 `ActiveAttempt` 分开建模:钩子不属于任何单个 attempt、不占并发位,
884
884
  * 也不参与 `RunFeedbackState` 的计数不变量——等待 setup 的
885
885
  * attempt 保持 `queued`,这行就是「为什么它们还在排队」的解释。`detail` 来自实验级
886
886
  * `ctx.progress`,后一条覆盖前一条。
@@ -1046,7 +1046,7 @@ export interface RunFeedbackState {
1046
1046
  * 这行就是「为什么它们还在排队」的解释。undefined = 当前没有在飞的预检。 */
1047
1047
  activePrecheck?: ActivePrecheck;
1048
1048
  /** 在飞的实验级钩子(experimentId → 运行级行状态),由 "experiment-hook" 事件增删、
1049
- * "experiment:progress" 更新 detail(见 docs/feature/experiments/cli.md「实验级钩子的显示」)。 */
1049
+ * "experiment:progress" 更新 detail(见 docs/feature/experiments/cli.md「实验级 Hook 的显示」)。 */
1050
1050
  experimentHooks: ReadonlyMap<string, ActiveExperimentHook>;
1051
1051
  /** 在飞的用例锁等待,按 experimentId 聚合(见 `ActiveLockWait`、docs/feature/experiments/cli.md
1052
1052
  * 「等待并发 run 的显示」)。由 "lock-wait" 事件增删/累计;没有等待用例的实验不出现在这个 map 里。 */
@@ -1178,7 +1178,7 @@ export type DurableFeedbackEvent =
1178
1178
  }
1179
1179
  /**
1180
1180
  * 实验级钩子(`ExperimentDef.setup` / 它返回的 teardown)的起止,由 runner 在钩子真正
1181
- * 开始/结束时各发一次(见 docs/feature/experiments/cli.md「实验级钩子的显示」)。`failed`
1181
+ * 开始/结束时各发一次(见 docs/feature/experiments/cli.md「实验级 Hook 的显示」)。`failed`
1182
1182
  * 只标记钩子自身的结局——setup 失败的每条 attempt 仍以 "failure" 事件逐条给出。human TTY
1183
1183
  * 用它维护运行级 active 行(不写 scrollback),append-only profile 起止各追加一行。
1184
1184
  */
@@ -1,4 +1,4 @@
1
- // report 聚合(report/aggregate.ts)与 view 榜单(view/app/lib/rows.ts)共用的聚合小工具。
1
+ // report 聚合(report/aggregate.ts)与 view 实验列表(view/app/lib/rows.ts)共用的聚合小工具。
2
2
  // 实验标签推导、token/成本求和、verdict 排序各只有一份 —— 否则同一个实验在终端和网页上
3
3
  // 会显示成两个名字 / 两组数。保持环境无关(纯函数,只 type import)。
4
4
 
@@ -36,7 +36,7 @@ export function displayExperimentName(id: string | undefined): string | undefine
36
36
 
37
37
  /**
38
38
  * 实验 id 的组推导:去掉末段的目录前缀("compare/bub-low" → "compare");
39
- * 无 "/" 的顶层实验不属于任何组,返回 undefined。view 榜单分组与自定义报告
39
+ * 无 "/" 的顶层实验不属于任何组,返回 undefined。view 实验列表分组与自定义报告
40
40
  * 的分组用同一份,两边的「组」永远指同一个东西。
41
41
  */
42
42
  export function experimentGroupOf(experimentId: string): string | undefined {
@@ -32,7 +32,7 @@ function attemptKey(attempt: AttemptHandle): string | undefined {
32
32
  }
33
33
 
34
34
  /**
35
- * 单行结果摘要:与榜单 Result 单元格同一条 display 契约(docs/feature/scoring/library/display.md)——
35
+ * 单行结果摘要:与默认报告 Result 单元格同一条 display 契约(docs/feature/scoring/library/display.md)——
36
36
  * 结构化 error 取一层 message 摘要,skipped 取理由,failed 取主失败断言的紧凑单行;passed 无摘要。
37
37
  */
38
38
  function rowSummary(result: EvalResult): string | undefined {
package/src/show/index.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  // 一次调用 = 范围 × 切片 × 形态(docs/feature/reports/show.md)。范围:eval id 前缀位置参数、
5
5
  // `@<locator>`(单元素范围)、`--exp`(可重复,>=2 进入对照语义)、`--results`、`--fresh`。
6
6
  // 切片(每个切片解析成一次报告组件装配,见 architecture.md「show 的切片是组件选择」):
7
- // 无证据 flag 且 --exp < 2 默认榜单(内建报告的 text 面;裸 show / eval 前缀 / 单个 --exp 都落在这里)
7
+ // 无证据 flag 且 --exp < 2 默认报告(内建报告的 text 面;裸 show / eval 前缀 / 单个 --exp 都落在这里)
8
8
  // 无证据 flag 且 --exp >= 2 对照矩阵(DeltaTable,接线点见 renderCompareSlice)
9
9
  // @<locator> 且无证据 flag 失败诊断首页(当前 report 的 attempt-input page)
10
10
  // --source / --execution / --timing / --diff[=路径] 证据切面(宿主本体,不渲染报告槽);
@@ -1038,7 +1038,7 @@ async function show(
1038
1038
  }
1039
1039
 
1040
1040
  // 缺省切片选择表(docs/feature/reports/show.md「缺省切片的选择规则」):`--exp` 出现两次以上
1041
- // 且没有被 `--report` 接管时是对照矩阵,不是报告槽的裸榜单——与 `--report` 互斥(缺省切片被
1041
+ // 且没有被 `--report` 接管时是对照矩阵,不是报告槽的裸默认报告——与 `--report` 互斥(缺省切片被
1042
1042
  // 报告树替换时对照矩阵不再适用)。
1043
1043
  if (flags.report === undefined && expSelectors.length >= 2) {
1044
1044
  const conditions = resolveCompareConditions(experimentIds, expSelectors);
@@ -1,6 +1,6 @@
1
1
  // cases: docs/engineering/testing/unit/reports.md
2
2
  // niceeval show 终端宿主的选择与错误反馈(「show 终端宿主的选择、时间轴与文案」与
3
- // 「show 的范围 × 切片正交」两个类别)。渲染产物——榜单/详情/证据切面的终端排版与结构——归
3
+ // 「show 的范围 × 切片正交」两个类别)。渲染产物——默认报告/详情/证据切面的终端排版与结构——归
4
4
  // docs/engineering/testing/e2e/report.md §4/§5 对真实运行产物验收,不在本文件重复。覆盖:
5
5
  // - --history 时间轴计算(attemptHistory):按 experimentId + evalId 分节、跨快照按身份键去重
6
6
  // (resume 携带的复印件不占行)、startedAt 升序、单行摘要与成本派生;
@@ -12,7 +12,7 @@
12
12
  // (renderEvidenceSections)是同一条代码路径,不是两份实现;
13
13
  // - 多 `--exp` 的范围校验(每个必须恰好解析到一个 experiment、命中多个按用法错误列出候选)、
14
14
  // `@<locator>` 与重复 `--exp` 互斥、缺省切片对照矩阵的占位接线点(renderCompareSlice)错误
15
- // 反馈;eval id 前缀命中单个 eval 时并入范围收窄后的默认榜单,不再有独立的单 eval 详情分支。
15
+ // 反馈;eval id 前缀命中单个 eval 时并入范围收窄后的默认报告,不再有独立的单 eval 详情分支。
16
16
  //
17
17
  // 跨快照合成 Selection 与去重的结构化语义(selectCurrentResults/现刻水位)已在
18
18
  // src/results/host-equivalence.test.ts 直接对 Selection 对象断言,不在本文件重复覆盖。
package/src/view/data.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  // 两扇门判定不分叉)、快照明细注入(locator / artifactBase)、skipped 透传、报告装载与逐页渲染
4
4
  // (裸跑填充 niceeval/report/built-in 的默认导出,--report 整槽替换,en / zh-CN 双语各渲染一遍)。
5
5
  // --report 只换报告定义,注入的 Scope 与裸跑同一份。统计口径整体住在报告页里
6
- // (报告组件的官方计算函数),viewData 不再携带 overview / 榜单这类统计产物,
6
+ // (报告组件的官方计算函数),viewData 不再携带 overview / 实验列表这类统计产物,
7
7
  // 见 docs/feature/reports/view.md「打开与收窄」。
8
8
 
9
9
  import { readFileSync, statSync } from "node:fs";
@@ -3,7 +3,7 @@
3
3
  //
4
4
  // viewData 只携带壳需要的东西:skipped、项目名与 run 元信息。attempt 明细不在这里——
5
5
  // 每份 attempt/<locator>.html 是独立静态文档(site.ts),不通过 viewData 这条通道下发;
6
- // 统计口径(KPI / 榜单 / 挑选警告)整体住在报告槽的静态 HTML 里(ExperimentComparison 或
6
+ // 统计口径(KPI / 实验列表 / 挑选警告)整体住在报告槽的静态 HTML 里(ExperimentComparison 或
7
7
  // --report 的报告自己算),壳与报告之间没有第二条数据通道。
8
8
 
9
9
  import type { LocalizedText } from "../../types.ts";