Files
InfoRSI/docs/结构.md
T
iomgaa 595b275a10 docs: 清理账本第一版设计留下的文档残留;任务书 03 加清理清单
WORK_LOG、结构.md 来源说明里"12 种记录""900–1400 行"已过时。任务书 03 新增"先清理第一版留下的东西":列明要删的文件、函数、测试、注释,并要求用搜索结果证明清干净。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 05:22:27 -04:00

386 lines
34 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# InfoRSI 代码结构
这份文件说明代码分成哪些模块、模块之间怎么依赖、流程按什么步骤推进、账本记哪些记录。研究方法本身以 `docs/方法.md` 为准;这里只说代码怎么组织来实现它。
来源:
- 用户 2026-10-01 认可"按负责一件事来切"、下面这套模块与可替换点,以及步骤清单和账本记录种类。
- 用户 2026-10-01 同意:提交的字段定义放 vocab,submissions 只判收不收;vocab 可放规范序列化和哈希两个函数,上限调到 600 行;执行后实际 1030 行,用户同意上限改为 1100 行。
- 用户 2026-10-02 同意:"全部只追加":账本用一张只追加的表,全部记录都不能改。
- 用户 2026-10-02 指出可见性、截止序号、通用唯一键都是过度设计:"每次给到派的材料有哪些"和"一开始灌进去还是让它去查"是分开的两件事;Jev 本质上是一种可以代替程序的判别器。据此:谁能看什么归 materials(按任务定材料),ledger 只存;只在方法要求"只能一次"处加唯一约束;Jev 不单独成记录。ledger 预期 500–900 行。
- 依据是两次开发调研。一次是模块切分,参考了 Parnas 1972 与 1979、Ousterhout、Cockburn 和同类项目的源码;一次是同类研究的实验设计。
---
## 一、切分原则
不按研究步骤切,按"以后可能会改的设计决定"切,一个模块藏住一个决定。换掉某个决定时,只改这一个模块。
判断一刀切得对不对,问这 7 个问题:
1. 这个模块藏住的是哪一个决定?说不出来,或者说出来的是"第几步",就是切错了。
2. 换掉这个决定,要改几个模块?应该只改 1 个。
3. 对外露出的函数和类型,是否比内部实现简单得多?
4. 依赖有没有绕成圈?下层能不能离开上层单独测试?
5. 纯计算的模块里,有没有读写文件、数据库、网络或模型?
6. 每样外部的东西,是不是只有一个模块直接碰它?
7. 同一份知识(阶段名单、谁能看见什么、某种提交有哪些字段)是不是只在一处定义?
---
## 二、模块
| 层 | 模块 | 藏住的决定 | 依赖 |
|---|---|---|---|
| 入口 | plugin(插件入口) | 用户在 Pi 里怎么操作:命令、状态显示、配置对话;文件锁;把各模块装配起来 | 装配时用到各模块 |
| 组织 | flow(流程) | 按步骤清单推进研究;每次启动走同一条恢复路径 | ledger、rules、materials、submissions、agents、runner、tasks、workspace、config、jev |
| 组织 | export(导出) | 导出给人看的格式 | ledger、rules、materials |
| 组织 | config(配置) | research.json 的字段、默认值、校验;把配置翻译成步骤清单 | 无 |
| 组织 | materials(材料) | 每个任务能看到哪些材料(方法.md 第三部分);第一条消息放哪些、什么顺序、怎么写;在这些材料范围内回答模型的查询 | ledger、rules |
| 组织 | submissions(收件) | 一份提交收下还是退回:先程序检查,再问 Jev(字段定义在 vocab) | jev |
| 外部 | ledger(账本) | 记录怎么存、怎么保证不可改、怎么从记录算出当前状态;花钱动作的登记 | 无 |
| 外部 | agents(角色会话) | Pi 的接口:开子会话、发工具和提示词、收提交、记用量 | 无 |
| 外部 | runner(运行器) | Docker 的用法:限时、限核、取消、记资源、取回产物 | 无 |
| 外部 | tasks(任务) | 一个任务怎么跑、怎么从原始产物独立算分(填圆的合法化也在这里) | 无 |
| 外部 | workspace(代码版本) | git 的用法:基线快照、实验员工作目录、冻结候选、代码差异 | 无 |
| 外部 | jev(Jev 判别) | 问法、阈值、校准 | 无 |
| 纯计算 | rules(研究规则) | 全部公式和常数;信念本、战绩、余额的计算 | 无 |
另有一个 **vocab**(共用词汇),所有模块都可以引用,上限 1100 行(多出来的主要是发给模型的字段说明)。一样东西要有两个互相不能引用的模块都用到,才放进 vocab;只有一个模块用的,放在那个模块里。它放:
- 共用的类型和名单:角色、研究者阶段、提交种类、指标定义、运行定义与运行结果、模型用量;
- 每种提交的字段定义(用 TypeBox 写,同一份定义既是类型,也用来检查收到的数据,也是发给模型的提交工具参数);
- 只有两个函数:规范序列化和哈希,保证"内容相同就得到同一个指纹"只有一种算法。
依赖只能往下,图中同一行的模块之间不互相依赖。谁具体能依赖谁,以上面的模块表为准,`npm run check` 按那张表检查。
```
入口 plugin
组织 flow
export
materials submissions config
外部 ledger agents runner tasks workspace jev
纯计算 rules vocab(谁都能用)
```
### 几条边界
- **给模型看什么只归 materials。** 每个任务开始时,materials 按方法.md 第三部分定下这个任务能看到的材料。哪些放进第一条消息、哪些等模型用查询工具去读,是同一份材料的两种给法,查询工具查不到这份材料以外的东西。ledger 不判断谁能看什么。
- **收不收一份提交,只在 submissions 一处判。** 跟状态有关的两条由 ledger 在写入时拒绝:这个阶段还开着吗;要替换的那一份是不是本人刚交的。
- **信念本**:数字由 rules 算,写成文字由 materials 负责,不单独存,每次现算。
- **runner 只管怎么跑,tasks 只管怎么判。** 两者互不认识,由 flow 串起来:先向 tasks 要运行定义,交给 runner 去跑,再把产物交回 tasks 算分。
- **"下一步做什么"只写在 flow 的一个纯函数里。** 每个步骤一个小文件。步骤文件里如果出现公式、字段名单或可见性判断,说明知识漏进来了,要挪回下层。
---
## 三、步骤清单
研究开始时,config 根据配置里的开关生成这份研究的步骤清单,连同每个决策点用哪条规则,一起冻结进账本。flow、导出、恢复都只读这份清单,不再读开关。被关掉的步骤不执行,账本里记一条"按配置跳过"。
**整份研究**
```
1. 冻结配置
2. 基线运行
3. 第零轮:写入口 → 讨论(1 或 2 次)→ 认领 → 分配 〔开关:第零轮〕
4. 一轮接一轮,直到余额用完
5. 导出
```
**每一轮**
```
1. 开轮:放信念本,处理留池候选
2. 提案
3. 判重合并
4. 第一次预测(看原始提案) 〔开关:第一次预测〕
5. 挑刺 〔开关:挑刺与回应〕
6. 回应与统一 → 协议冻结 〔开关:挑刺与回应〕
7. 第二次预测(看冻结协议)
8. 选批 〔规则:选批规则〕
9. 对每个入选候选:实现 → 核验 →(不通过:修复 → 再核验)→ 正式运行
10. 整批公开,记分数账和信息账
11. 采纳
12. 若采纳的改法有 2 个以上因子: 〔开关:消融〕
列格 → 解释 → 选格 → 对每个选中的格:消融实现 → 核验 → 运行 → 结算
〔规则:选格规则〕
13. 收尾,更新信念本
```
---
## 四、账本记录
账本只存发生过的事。信念本、战绩、余额、"现在进行到哪一步"都不存,每次从记录现算。
**全部只追加。** 所有记录放在同一张表里,每一行是:序号(自动递增,就是时间先后)、种类、内容(JSON)、内容的哈希。整张表禁止修改、禁止删除,由数据库触发器保证。要更正就追加一条新记录;"开"和"关"、"替换"也都写成新记录。
恢复时只核对、不重做写入(CLAUDE.md"中断后怎么恢复"),所以记录照写就是,不需要通用的去重。只在方法要求"只能有一次"的地方加唯一约束,重复了就报错:一次运行的确认启动、一次运行的结果、一次消融的结算。运行编号由 flow 起;确认没启动、退还名额后要重试,就起一个新编号。
| # | 记录 | 内容 | 谁写入 |
|---|---|---|---|
| 1 | 研究配置 | 冻结的配置、步骤清单、每个决策点用哪条规则、方法参数、提示词哈希 | flow(内容由 config 生成) |
| 2 | 阶段 | 每个阶段开一条、关一条;关闭即公开 | flow |
| 3 | 提交 | 各种提交的每一版:入口、讨论、志愿、提案、两次预测、挑刺、回应、解释、收尾、实现、核验;私人笔记的每一版。阶段关闭后以最后一版为准,此后由 ledger 拒绝再写。被退回的提交也记,附退回理由(含 Jev 的原始概率和结论) | flow(经 submissions 判定后) |
| 4 | 冻结协议 | 每个候选的冻结版本:因子清单、保障清单、实现条款、指标登记 | flow |
| 5 | 作者自评 | 封存时的三个数;解封时追加一条解封记录 | flow |
| 6 | 冻结代码 | 每份候选代码和消融格代码的版本号,以及因子位置表 | flow(版本号由 workspace 给出) |
| 7 | 运行 | 每次正式运行三条:登记要跑(占名额);确认启动(扣次);结果(分数、合法化、指标、答案路径、资源) | flow(结果由 runner 与 tasks 给出) |
| 8 | 决定 | 程序做的每个决定:选批、采纳、选格、押的因子、入口分配、判重合并。每条存规则名、规则版本、方法参数、种子、全部输入、输出;用到 Jev 的(判重合并),输入里带 Jev 的原始概率 | flow(由 rules 计算) |
| 9 | 结算 | 每格的结局、撑几成、配合关系标签、每条解释的确认或否定、世界比特、惊讶 | flow(由 rules 计算) |
| 10 | 用量 | 模型调用三条:开始(附这次任务的全部材料)、每次回复的用量、结束;整个环境的用量。只记录 | agents、runner |
| 11 | 事件 | 违规记录、"按配置跳过"、"没测"及原因、停下的原因 | flow |
Jev 是一个判别器,和程序检查地位相同,不单独成一种记录:它的原始概率和结论,记在它判断的那件事里(第 3 种的退回理由、第 8 种的判重合并)。
**写入时由 ledger 拒绝的几种情况**:阶段已关闭还要写提交;要替换的那一份不是本人在这个阶段刚交的;没有"确认启动"就写运行结果("确认没启动"这种结果除外);这次消融已经有格启动了才冻结解释。
---
## 五、可替换点
论文实验要换掉的部件,按种类用最轻的办法换:
| 种类 | 例子 | 换法 |
|---|---|---|
| 外部服务 | Pi 会话、Docker 运行器、任务、Jev | 接口。Jev 另配一个"永远判不同"的空实现,用来关掉判重 |
| 决策规则 | 选批:批内最好期望、均匀随机。选格:信息价值减成本、全测、随机同格数、都不测。以后可能加合并方式 | 纯函数,登记在 rules 里的"名字 → 函数"表里,配置写名字 |
| 方法参数 | N、M、批量、运行次数、因子数上限、u、衰减、开放预留 | 配置值,不写成常数,也不用环境变量。分两层:用户配置(配置对话会问);方法参数(做实验时才改,配置对话不问) |
| 步骤开关 | 消融、挑刺与回应、第零轮、第一次预测 | 配置值,由 config 翻译进步骤清单 |
| 模型与提示词 | 每个角色、每位研究者用哪个模型;提示词目录 | 配置值;账本记下每份提示词文件的哈希 |
对照组"朴素循环"不另写流程,它就是一组开关的命名预设。
为了让换规则的实验做得对,结构上守住下面几条:
1. **开关只在一处被读取**:就是第三部分的步骤清单。互相冲突的组合在配置校验时报错,比如关掉了预测,选批却不是随机。
2. **决策函数是纯函数,输入全部从账本读。** 每条决策记录存下规则名、规则版本、方法参数、随机种子、全部输入和输出。种子由研究编号、轮次、版本算出,不用全局随机数。平票按固定规则处理。决策函数要导出,重放脚本和核对脚本直接调用它,不另抄一份公式。这样同一批记录换一条规则,就能离线重算。
3. **衡量好坏的尺子只有一把。** 比特、惊讶、覆盖率永远用同一个固定算法,从每个人的原始范围算出来,不跟着决策规则一起变。
4. **一份研究的配置在开始时冻结进账本**,恢复时以冻结的那份为准。
5. **只提供跑通过的组合。** 每个命名预设至少有一条小规模的跑通测试。
---
## 六、模块化程度与检查
- 一个 npm 包,每个模块一个目录。别的模块只能通过目录下的 `index.ts` 引用它。
- 用 dependency-cruiser 在 `npm run check` 里强制以下规则:
- 不许循环引用;
- 每个模块只能依赖第二部分表里列出的模块;
- 不许绕过 `index.ts` 直接引用模块内部的文件;
- rules 和 vocab 不许引用文件、数据库、网络、子进程和 Pi;
- 只有 ledger 能用 SQLite,只有 agents 和 plugin 能用 Pi,只有 runner 和 workspace 能起子进程;
- tasks 不许引用 runner。
- 不拆成多个包,也不做 TypeScript 分项目编译。
---
## 七、规模
下表是粗估。动手写某个模块之前,由用户逐个确认;写的过程中超过预期一倍,就停下来检查。
| 模块 | 预期行数 |
|---|---|
| plugin | 600–1000 |
| config | 300–600 |
| flow | 2000–3500 |
| ledger | 500–900 |
| rules | 1500–2500 |
| submissions | 600–1000 |
| jev | 300–500 |
| materials | 1000–1800 |
| agents | 800–1300 |
| workspace | 300–600 |
| runner | 500–900 |
| tasks | 契约 150–300;填圆 600–1000,另有 Python 文件 |
| export | 500–900 |
| vocab | 上限 1100 |
---
## 八、各模块对外的函数与类型
写到哪个模块时,再把它对外的函数和类型补在这里。
### vocab
下面是 `src/vocab/index.ts` 导出的全部内容。标"字段定义"的,是一份 TypeBox 定义,同名的 TypeScript 类型也一起导出:同一份东西既当类型用,也能在运行时检查数据(`Value.Check`),还能直接当发给模型的工具参数。
**两个函数**
- `canonical(value)`:规范序列化。对象的键排序后再拼成字符串,数字必须是有限数,只接受纯 JSON;内容相同就一定得到同一个字符串。
- `hash(value)`:对规范序列化的结果算 sha256,得到 64 位十六进制的指纹。
**基础**
- `Json`(类型):任意纯 JSON 值。
- `Id`(字段定义):编号的格式,只许字母、数字和 `._-`,首字符是字母或数字,最长 128 个字符,因为编号会被拼进文件路径和命令行。
- `DIRECTIONS`、`Direction`(字段定义):指标方向,只有越大越好(maximize)和越小越好(minimize)两种。
- `Measured`(字段定义):测到 / 测不到。测到带值,测不到带原因,所有可能测不到的量都用它,不拿 0 或 null 冒充。
**名单**
- `ROLES`、`Role`:三个角色,研究者、实验员、核验员。
- `STAGES`、`Stage`:有人交提交的各个阶段,按流程先后排;程序自己做的步骤不在里面。
- `SUBMISSION_KINDS`、`SubmissionKind`:每种提交属于哪个阶段、由哪个角色交,各模块都从这张表取。
**指标**
- `METRIC_LAYERS`、`MetricLayer`:指标的三个层次,最终、常规辅助、假设专用。
- `MISSING_POLICIES`、`MissingPolicy`:测不到时怎么办的两档,缺了只记缺失、缺了整次作废。
- `MISSING_POLICY_EFFECTS`:两档各自后果的白话说明,字段说明和给模型的材料共用这一份。
- `HypothesisMetric`(字段定义):研究者在提案里登记的一条假设专用指标。
- `MetricDefinition`(字段定义):一条完整的指标定义,带编号和层次。
**运行**
- `RunDefinition`(字段定义):tasks 交给 runner 的运行定义,写明命令、工作目录、按 sha256 钉死的镜像和运行时、时限、核数和环境变量;候选进程不继承宿主的环境变量。
- `ProcessResult`(字段定义):runner 交出的进程层面结果,分没启动、正常退出、超时、被取消四种;启动过的带资源用量。
- `VERDICTS`、`Verdict`:一次运行的判定,算数、不算数、判不了三选一。
- `ANSWER_PATH_KEY`、`SAFEGUARD_TRIGGERS_KEY`:候选在指标文件里多写的两个保留键名,`answer-path` 和 `safeguard-triggers`。
- `AnswerPath`(字段定义):读到的答案路径原样字符串,或读不到及原因;在不在位置表里由拿得到位置表的模块现算。
- `SafeguardTriggers`(字段定义):读到的"保障短名 → 动手次数"原样内容,或读不到及原因。
- `JudgedResult`(字段定义):tasks 从原始产物独立判分的结果,包括判定和理由、分数、各指标取值、答案路径、保障动手次数和任务自己的附加记录。
- `ModelUsage`(字段定义):一次模型调用的用量,四种 token 数和价格,每一项都可能测不到。
**提交**
- `Range`(字段定义):三个数 q1、q5、q9,即一个分数有一成、一半、九成可能低于多少。
- `SUBMISSION_SCHEMAS`:每种提交的字段定义,键与 `SUBMISSION_KINDS` 相同;同一份定义是类型、收件格式检查和提交工具参数。
- `Submission<K>`(类型):某种提交的内容类型,例如 `Submission<"proposal">`。
### rules
下面是 `src/rules/index.ts` 导出的全部内容。rules 是纯计算:输入数字,输出数字,不碰文件、数据库和模型,也不用全局随机数。λ、ε、已知最好、每批上限、余额这些参数都由调用方传进来,rules 里只写死方法.md 6.11 标"固定"的几个常数。三个数一律用 vocab 的 `Range`。编号(候选、研究者、入口、因子、解释)一律按自然序比较:数字部分按数值大小比,所以 c2 排在 c10 前面。
几个反复出现的词:**折线**是把一个人的三个数画成"分数低于 x 的把握"的分段直线(6.2);**合并分布**是几条折线按权重加起来的结果(6.3);**改进量**是分数比基线好了多少,正数表示变好,越小越好的任务也换算成正数为好(6.1)。决定类函数的返回值里带着写决定记录要用的中间数,不只返回"选了谁"。
**常数与基础**
- `INTERACTION_CUT`:配合关系标签里相对交互量的界限 0.2(6.6"配合关系标签")。
- `INDISPENSABLE_SUPPORT`:判"缺一不可"的撑几成界限 0.9(6.6)。
- `NET_TOLERANCE`:选格时比较净值的容差 1e-12,差距在它以内的组合当作一样好(6.7"选格")。
- `GRID_COMBINATION_CAP`:只测一部分格时,网格组合总数的上限 4,000,000(6.7"信息价值")。
- `GRID_SUBDIVISIONS`:网格里每段最多再等分 20 份(6.7"信息价值")。
- `epsilonFloor(ε)`:算 ε/100;采纳线下限、剩余空间下限、比特格宽三处共用这一个函数,保证末位一致(6.11"跟随 ε")。
- `improvement(from, to, direction)`:从 from 到 to 按指标方向好了多少,越大越好时是 to − from,越小越好时是 from − to(6.1)。
- `compareIds(a, b)`:按自然序比较两个编号,供所有排序和"编号最小"的判断使用;p01 和 p1 这类逐段相同的编号再按整串定先后,不会判成相等。
- `combinations(n, k)`:列出从 0..n−1 里选 k 个的全部组合,按字典序排,选批和选格列组合时用。
**范围与合并分布(6.1–6.3)**
- `Point`、`Knots`(类型):折线上的一个点(横坐标,低于它的把握),以及按横坐标严格递增排列的一串点。
- `Component`、`Mixture`(类型):合并分布的一个成分(一条折线加它的权重),以及成分的列表,权重加起来是 1。
- `personKnots(range)`:把一个人的三个数变成五个点的折线,两端各补一段与相邻半宽相同的尾巴(6.2)。
- `below(knots, x)`:读折线在 x 处"低于 x 的把握"。
- `knotsMean(knots)`:折线所代表的分数的平均值(期望)。
- `density(knots, x)`:折线在 x 处的斜率,也就是把握在这一点有多集中(密度);押的因子更新权重时用(6.8)。
- `mapKnots(knots, f, decreasing)`:把折线的横坐标换到另一把刻度上;换算是反向时点序倒过来、把握换成 1 减原把握。
- `reserveKnots(lines)`:开放预留,即给"大家都没想到的结果"留的那一份:取所有折线的最低点到最高点,左右各再放宽一半,在上面均匀铺开(6.3)。
- `authorShares(authors)`:每条解释的占比,研究者之间等权,同一人的几条平分(6.3"合并"、6.7"成分与权重")。
- `mixtureBelow(m, x)`:合并分布在 x 处"低于 x 的把握"。
- `breakpoints(m)`:合并分布全部折点的横坐标,去重、升序。
- `mapMixture(m, f, decreasing)`:把合并分布的每个成分都换到另一把刻度上,权重不变。
- `forwardMixtures(candidates, λ)`:正向每个候选的合并分布,(1 − λ) × 各人折线平均 + λ × 开放预留,开放预留由这次选批的全部候选、全部人共用(6.3"正向")。
- `ablationCellMixture(entries, λ)`:消融一格的合并分布,各条解释按 `authorShares` 分 1 − λ,这一格自己的开放预留占 λ(6.3"消融")。
- `toImprovement(m, b, direction)`:把合并分布从分数原值换算成相对基线 b 的改进量;越小越好时刻度反向,一成和九成随之对调(6.1)。
- `mixtureQuantile(m, p)`:合并分布的分位点,即"有 p 的把握低于多少";只给人看,不参与决定。
- `mixtureRange(m)`:合并分布的一成、一半、九成,按分数原值,消融格显示"大家合起来的范围"用。
- `forwardMergedRange(imp, b, direction)`:正向候选"大家合起来的范围",在改进量上读三个数再换回分数原值。
- `integrateUpperTail(ds, from)`:按段精确算 ∫[1 − ∏F] dt,正向的批内最好期望和消融全测时的信息价值共用这一个积分。
**正向:入池、选批、采纳(6.4、6.5,4.3 ⑫)**
- `lossProbability(imp, ε)`:候选"比基线低 ε 以上"的把握;严格小于一半才入池(6.4"入池")。
- `batchValue(imps)`:一组候选的批内最好期望 V(S),即这批里最好的那个预计比基线好多少,低于基线按 0 算(6.4)。
- `BatchInput`(类型):两条选批规则共用的输入:候选及各人的三个数、基线、方向、ε、λ、每批上限、余额、种子。
- `BatchDecision`(类型):选批结果,含 6.4"选批记录写入"的全部内容:参数、批量 k、每个候选的合并范围和是否入池、各组合的 V、选中的组合及其 V、候选池的 V、分数尺读数。
- `selectBestExpected(input)`:选批规则"批内最好期望",在候选池里列出全部组合取 V 最大的,V 完全相等时取编号小的组合(6.4)。
- `selectUniformRandom(input)`:选批规则"均匀随机",用种子从全部候选里抽,不看入池门槛;入池、合并范围、分数尺读数照样算出来记下(第十一部分)。
- `AdoptionLineInput`(类型):算采纳线要的基线 B、已知最好 K\*(没有时为 null)、ε 和方向。
- `adoptionLine(input)`:采纳线(6.5),返回线的值和 (K\* − B) ÷ 4 的原值;没有已知最好时是 ε,结果不低于 ε/100。
- `adopt(input)`:采纳判断,只看有有效分数的候选,最好的那个比基线高出采纳线以上才采纳;返回采纳线、最好的候选及其改进量和采纳结果,够写采纳记录。
**消融结算(6.6,4.3 ⑬ ⑰)**
- `CellOutcome`(类型):一格的五种结局:有效分数、证据不足、没测、跑不起来、一起关(带实际关掉的因子和可能的分数)。
- `AblationCell`(类型):一格,即一个因子和它的结局。
- `AblationExplanation`(类型):一条解释,带作者和它对每一格给的三个数。
- `listCells(factors)`:列格,被采纳改法的每个因子各一格,按因子编号排(4.3 ⑬)。
- `totalGain(baseline, full, direction)`:总提升 G = f(完整) − f(基线);G ≤ 0 说明上游选错了改法,直接报错(6.6"撑几成")。
- `supportOf(baseline, full, off, direction)`:某个因子撑几成,即关掉它后损失的分数占总提升的比例,不截断(6.6)。
- `SynergyLabel`(类型):配合关系标签的代号,六种:关掉反而更好、不全、缺一不可、互补、替代、各管各;中文说明以后由 materials 写。
- `synergyLabel(supports)`:按 6.6 那张表从上往下判出标签,同时返回各格撑几成之和与相对交互量(有格没测出有效分数时这两个数为 null)。
- `sharedSettings(cells)`:判断哪些"一起关"的格其实是同一种设置(关的因子集合相同),给出该沿用哪一格的结果(6.6)。
- `ExplanationVerdict`(类型):一条解释在一格上的判定,确认或否定。
- `judgeExplanations(explanations, cells)`:每条解释在每个有效格上,实测落在它的一成到九成之间(含两端)记确认,否则记否定(6.6)。
- `inseparableGroups(judgments)`:找出在所有有效格上确认与否定完全相同的解释,归成"现有测法分不开"的组(6.6)。
- `ablationFinding(input)`:消融中发现,找出比当前基线高出采纳线以上的格,几格都过线时取分数最好的、同分取因子编号小的;返回采纳线、(K\* − B) ÷ 4、全部过线的格和选中的格(4.3 ⑰)。
- `SettleInput`(类型):一次消融结算的输入:基线、完整分数、方向、ε、已知最好、λ、被采纳改法的因子清单、各格结局、各条解释。清单里每个因子都要有一格,缺了直接报错。
- `settleAblation(input)`:一次消融的完整结算,给出 G、每格的撑几成和合并范围、有效格的世界比特、惊讶和分歧量、配合关系标签、确认与否定、分不开的组、消融中发现(4.3 ⑰、6.6、6.9);押的因子另由 `chooseBet` 算。
**信息价值与选格(6.7、6.8)**
- `OPEN_RESERVE`:成分名单里开放预留的名字,排在最后。
- `AblationModelInput`(类型):建成分模型要的输入:基线、完整分数、方向、已知最好、ε、λ、因子编号、各条解释。
- `AblationModel`(类型):成分模型:因子、成分(各条解释加开放预留)、起始权重、G、剩余空间 h、每格每成分的折线(分数原值和撑几成两种刻度)及期望、每格的事前期望撑几成。
- `remainingSpace(full, knownBest, ε, direction)`:剩余空间 h,有已知最好时是 max(K\* − f(完整), ε/100),没有时是 1(6.7"方向收益")。
- `ablationModel(input)`:建成分模型,每条解释一个成分、开放预留一个成分,解释合起来占 1 − λ(研究者等权、同一人平分),开放预留占 λ(6.7"成分与权重")。
- `gridSize(k)`:测 k 格时每格的小段数 m,即满足 m^k ≤ 4,000,000 的最大整数(6.7"信息价值")。
- `cellGrid(knots, k)`:把一格按折点切成小段,返回各小段中点和每个成分在各小段上的把握;小段数的规则按 6.7 原文。
- `measuredGrid(model, c, k)`:模型里第 c 格的网格,在分数原值上切段,再把中点换算成撑几成。
- `informationValueExact(model)`:全部格都测时的信息价值,逐段精确积分。
- `informationValueGrid(model, S)`:用网格算的信息价值,不论测几格都走网格,主要用来和精确算法互相对照。
- `informationValue(model, S)`:信息价值 VOI(S),即测了 S 这几格之后,挑出最该押的因子能比现在多挣多少(6.7);全测走精确积分,只测一部分走网格,空集是 0。
- `ComboParams`(类型):算价值与成本要的余额、每批上限、知识被用上的概率 u、衰减 r。
- `ComboValue`(类型):一个测格组合的 VOI、R̂、m′、价值、成本、净值(6.7"价值减成本")。
- `evaluateCombos(model, params)`:列出格数不超过"余额 − 1"的全部非空组合并算价值、成本、净值,另给 ĝ₀ 的原值。
- `CellRuleInput`(类型):四条选格规则共用的输入,即成分模型的输入加 `ComboParams` 和种子。
- `UntestedReason`(类型):一格没测的原因:剩余次数不够、信息价值不足以抵过成本、随机没抽中、规则是"都不测"。
- `CellDecision`(类型):选格结果,含 6.7 要求附上的全部数字:参数、种子、G、h、成分与起始权重、各因子的事前期望收益、ĝ₀、全部组合、选中的格及其净值,以及每一格测不测、没测的原因和含它的净值最大组合。
- `topCombo(combos)`:在给定的组合里挑净值最大的,差在 1e-12 以内算一样好,再先取格数少的、后按因子编号比(6.7"选格"第 2 条)。它不管净值是否大于 1e-12,所以也用来挑"含这一格的最好组合"。
- `pickByNet(combos)`:按净值挑要测的组合。先只留净值大于 1e-12 的组合,一个都没有就一格都不测;再在留下的组合里用 `topCombo` 挑。
- `selectByValue(input)`:选格规则"信息价值减成本"(6.7"选格")。
- `selectAll(input)`:选格规则"全测",按因子编号测前"余额 − 1"格(第十一部分)。
- `selectRandomSameCount(input)`:选格规则"随机抽同样多的格",格数和"信息价值减成本"会选的一样,用种子抽(第十一部分)。
- `selectNone(input)`:选格规则"都不测"(第十一部分)。
- `BetResult`(类型):押的因子的结果:更新后的成分权重、权重是否无从更新、各因子的方向收益(实测换算的或估计的)、挑出的因子及其预测收益、押或不押的两种情况、关掉反而更好的格。
- `chooseBet(input)`:押的因子,用有效格的实测更新各成分的权重,再挑方向收益最大的因子;有格关掉反而更好或估计收益不为正时不押,实测落在所有成分之外时保持起始权重(6.8)。
**信息账(6.9)**
这一组是方法里"唯一的尺子",不随选批、选格规则变,一律在分数原值上从本批基线 b 起按格宽切小格。
- `bitWidth(ε)`:格宽 Δ = ε/100。
- `entropyBits(ps)`:一组把握的拿不准程度 −Σ p log₂ p,单位是比特。
- `worldBits(m, origin, width)`:世界比特,即合并分布在宽 Δ 的小格上有多拿不准。
- `cellIndex(origin, width, v)`:实测 v 落在第几个小格,和切格用同一套边界。
- `surprise(m, origin, width, value)`:惊讶 = −log₂(事前给实测所在小格的把握),返回格号、事前把握和惊讶值;事前把握为 0 时惊讶记"测不到"并写明原因。
- `disagreement(entries, origin, width)`:分歧量,大家平均后的世界比特减去各人世界比特的平均,量的是人与人之间的差别,不掺开放预留,只记录。
- `Placement`(类型):落点四段:低于一成、一成到一半、一半到九成、高于九成。
- `placement(range, v)`:实测落在一个人范围的哪一段。
- `covers(range, v)`:实测是否落在一成到九成之间(含两端),也是 6.6 里"确认"的判据。
- `coverage(samples)`:落点四段的计数和覆盖率;一条样本都没有时覆盖率记"测不到",不记 0。
**余额与战绩(第七部分、6.10 第 4 条)**
- `RunState`(类型):一次正式运行在账上的三种状态:已预留还没核对出结果、确认启动、确认没启动。
- `runBalance(total, runs)`:从运行记录数出已扣次数、占用名额和余额;确认启动的扣一次,已预留的先占着名额,确认没启动的退还。只数运行次数,不算计算时间。
- `forwardBatchSize(batchCap, balance)`:本轮正向批量 k = min(每批上限, 余额)。
- `ablationCellLimit(balance)`:消融最多测"余额 − 1"格,余额为 0 或 1 时是 0。
- `Phase`(类型):正向或消融。
- `Tally`(类型):一个人的战绩:总数、中位数偏高几次、偏低几次、被穿过上沿几次、下沿几次、包住几次、落点四段计数。
- `trackRecord(samples)`:按研究者、按正向与消融分开数战绩,只用来显示,不改任何权重(6.9、6.10)。
- `authorVsMerged(items, direction)`:"作者自评 vs 大家合并",给出作者比大家乐观多少,以及实测落在两个范围的哪一段;只收已经跑过、有有效成绩的候选(6.10 第 4 条)。
**入口分配、种子与规则登记表(4.2、第九部分、第十一部分)**
- `EntryAssignment`(类型):一个研究者分到的入口,以及它是第几志愿(按剩余入口分到的为 null)。
- `assignEntries(input)`:第零轮的入口分配,按志愿一轮一轮分,争同一个入口时先给作者、再给编号最小的人,志愿用完的人按编号拿剩下的入口;结果里带志愿序号,够写分配记录(4.2"分配规则")。
- `decisionSeed(input)`:决定的种子,由研究编号、轮次、版本经 vocab 的 `hash` 算出(第九部分)。
- `seededRandom(seed)`:从种子确定地展开一串随机整数,同一个种子永远得到同一串数,不用 `Math.random`。
- `seededSample(items, size, seed)`:用种子从一组编号里不放回地均匀抽 size 个,结果只取决于种子和编号集合,与传入次序无关;候选和因子都这样抽。
- `BATCH_RULES`、`BatchRuleName`:选批规则登记表,名字 → 函数和版本号,两条:批内最好期望、均匀随机。
- `CELL_RULES`、`CellRuleName`:选格规则登记表,四条:信息价值减成本、全测、随机抽同样多的格、都不测。
- `runBatchRule(name, input)`:按名字跑一条选批规则,结果带上规则名和版本,flow 写决定记录时从这里取。
- `runCellRule(name, input)`:按名字跑一条选格规则,结果带上规则名和版本。