Files
iomgaa 30e4d98ed2 docs: 结构.md 调整 vocab 范围,新增任务书 01-vocab
用户 2026-10-01 同意:提交字段定义放 vocab、submissions 只判收不收;vocab 可放规范序列化与哈希两个函数,上限 600 行。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 22:56:50 -04:00

167 lines
11 KiB
Markdown
Raw Permalink 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.
# 任务书 01:vocab(共用词汇)与工具链
这是 InfoRSI 的第一个代码任务。项目里现在只有文档,没有代码。这个任务做两件事:
1. 搭好工具链:npm 包、TypeScript、测试、依赖方向检查;
2. 写 vocab 模块:各模块共用的类型、名单、提交字段定义,以及两个函数。
本任务书的内容已由用户和监督者在 2026-10-01 一起确定。下面说的"监督者",是在参考项目目录里和用户讨论设计的另一个会话。
## 开工前先读
- `CLAUDE.md`:全部。
- `docs/结构.md`:
- 第一部分(切分原则);
- 第二部分(模块表,以及表下面讲 vocab 的那一段);
- 第六部分(模块化程度与检查);
- 第七部分(规模)。
- `docs/方法.md`:
- 第二部分(核心概念);
- 第三部分(角色);
- 4.2、4.3(流程里的各个阶段);
- 第五部分(每种提交,**这是提交字段的唯一依据**);
- 第七、八部分(运行要记录什么)。
- 参考项目(只读,不要改):`/home/iomgaa/Projects/RivalBits`
- `src/core/types.ts`:旧的共用类型。下面"保留与删除"一节说明哪些要、哪些不要;
- `src/rounds/submissions.ts`、`src/rounds/task-submissions.ts`:旧的提交字段,里面混着收件检查。只借字段本身,按方法.md 第五部分重写;
- `package.json`、`tsconfig.json`:版本号可以参考。
## 一、工具链
- 建一个 npm 包,`"type": "module"`,Node ≥ 22.19(本机是 22.22.2)。
- 这次只装这次用得到的依赖:`typebox` 1.3.7、`typescript`、`@types/node`、`dependency-cruiser`。
- Pi 的包等写 agents 模块时再装。
- Pi 0.85.1 用的也是 `typebox` 1.3.7,这次定的字段定义以后要直接当 Pi 工具的参数用,所以版本必须一致。
- `npm run check`:TypeScript 类型检查加 dependency-cruiser,两项都要过。
- `npm test`:用 Node 自带的 `node --test`。
- dependency-cruiser 把 `docs/结构.md` 第六部分列的规则全部写进去,模块按 `src/<模块名>/` 的目录来认:
- 依赖方向按第二部分的模块表;
- 不许循环引用;
- 不许绕过 `index.ts` 直接引用模块内部的文件;
- rules 和 vocab 不许引用文件、数据库、网络、子进程和 Pi;
- 只有 ledger 能用 SQLite,只有 agents 和 plugin 能用 Pi,只有 runner 和 workspace 能起子进程;
- tasks 不许引用 runner。
现在只有 vocab 一个目录,但规则要一次写全,后面的模块建目录就自动受检查。
- 要证明这些规则真的会报错,不能只是写了配置:临时写几处违规的引用(比如 vocab 引用 `node:fs`、一个模块绕过 `index.ts`),把 `npm run check` 的报错输出记下来,然后删掉这些违规引用。
## 二、vocab 放什么
判断标准(来自结构.md):一样东西要有两个互相不能引用的模块都用到,才放进 vocab;只有一个模块用的,放在那个模块里。上限 600 行,预期 450–600 行。
建议分四个文件,由 `src/vocab/index.ts` 统一对外。文件名和英文标识符你来定,以读得懂为准。
### 1. 基础
- `Json` 类型。
- "测到 / 测不到"的取值:测到就带值,测不到就带原因。全项目凡是可能测不到的量(资源用量、分数、指标、价格)都用它,不用 0 或 null 冒充测不到。
- 指标方向:越大越好、越小越好,只有这两种。
- 编号的格式:只允许字母、数字和 `._-`,长度有限。编号会被拼进文件路径和命令行,所以要限制。写成一条 TypeBox 的字段规则,各字段定义里复用,不写成函数。
- 两个函数:
- **规范序列化**:对象的键排序后再拼;数字必须是有限数;只接受纯 JSON 对象。这样内容相同就一定得到同一个字符串;
- **哈希**:对规范序列化的结果算 sha256。
这是 vocab 里仅有的两个函数。
### 2. 名单
- **三个角色**:研究者、实验员、核验员。
- **研究者阶段和提交种类**:按方法.md 4.2、4.3 和第五部分列出。每种提交写清两件事:属于哪个阶段、由哪个角色交。这份对应关系写成一张常量表,以后 ledger、materials、submissions、flow、agents 都从这里取,不在别处另写。
- 监督者整理的对应关系如下,作参考。以方法.md 为准,对不上时按方法.md 来,并在最后的报告里写出差别:
| 提交 | 阶段 | 角色 |
|---|---|---|
| 入口 | 写入口 | 研究者 |
| 讨论 | 讨论 | 研究者 |
| 志愿 | 认领 | 研究者 |
| 提案 | 提案 | 研究者 |
| 第一次预测 | 第一次预测 | 研究者 |
| 挑刺 | 挑刺 | 研究者 |
| 回应 | 回应 | 研究者 |
| 统一 | 回应 | 研究者 |
| 第二次预测 | 第二次预测 | 研究者 |
| 实现 | 实现 | 实验员 |
| 修复 | 实现 | 实验员 |
| 核验 | 核验 | 核验员 |
| 消融实现 | 消融实现 | 实验员 |
| 消融核验 | 消融核验 | 核验员 |
| 解释 | 解释 | 研究者 |
| 收尾 | 收尾 | 研究者 |
- 程序自己做的步骤,比如判重、选批、采纳、选格,不是提交阶段,不放这里。步骤清单归 config。
- 私人笔记不在这次范围内。
### 3. 运行与指标
- **指标定义**,包括:编号、层次(最终 / 常规辅助 / 假设专用)、含义、单位、方向、怎么采样和汇总、"测不到时怎么办"。
- "测不到时怎么办"只有两档:缺了只记缺失;缺了整次作废。
- 每一档的后果用一句白话写在常量里,字段说明和给模型看的材料都用这一份。白话的内容见方法.md 第五部分"指标"。
- **运行定义**:tasks 交给 runner,告诉它怎么起这个进程。要能回答这几件事:
- 命令和工作目录;
- 镜像:按 sha256 钉死,不接受 tag;运行时必须写明;
- 限时、核数;
- 环境变量:候选进程**不继承**宿主的环境变量。类型上只允许写 false。
- 原因:参考项目实测过,宿主环境被污染时,同一份代码的分数会从 0.9598 悄悄变成 0.8849,退出码是 0,没有任何报错。这属于"出错后无法察觉"的那一类。
- 参考项目里环境变量分成两块("协议那块"和"逐候选那块"),是为了算两个"可比条件哈希"。那两个哈希这次删掉了,所以这里只要一块。
- **运行结果**,分两层:
- runner 交出的进程层面结果:有没有启动;以什么方式结束(正常退出、超时、被取消、没启动);退出码;CPU 秒、墙钟时间、峰值内存。资源用量都可能测不到,用"测到 / 测不到"表示。
- tasks 交出的判分结果:
- 判定:三选一,算数 / 不算数 / 判不了,附理由;
- 分数;
- 各指标的取值;
- 答案路径和各条保障动手的次数(方法.md 第五部分"答案路径")。读不到,或者读到的取值不在位置表里,都要有明确状态;
- 一份任务自己的附加记录,任务想记什么就记什么,比如填圆的合法化。
- **模型用量**:普通输入、缓存命中、缓存写入、输出四种 token 数,加上价格。价格可能测不到。
### 4. 提交字段
- 按方法.md 第五部分,每种提交写一个 TypeBox 字段定义。同一份定义要同时当三样东西用:类型、收件时的格式检查、发给模型的提交工具参数。
- 字段说明也写在定义里,它会原样发给模型。
- 方法.md 要求每个字段都写明出口,比如"只有一个因子就写一个"、"不适用:原因"、"没有:为什么";
- 说明用中文。
- **三个数**是一个共用的定义:q₁、q₅、q₉ 三个有限数。
- 正文统一是一个 markdown 字符串字段,程序不拆它。
- 不需要写的字段:
- 只存不读的栏目、程序自己推得出的栏目,不设(方法.md 第五部分总原则);
- 编号由程序分配的(候选编号、挑刺编号),不放进模型要填的字段。
- 跨字段的规则**不在这里写**,留给以后的 submissions 模块。比如:q₁ ≤ q₅ ≤ q₉;因子数不超过上限;同一份提案里两个因子不能延续同一个因子;解释最多 M 条。字段定义只管单个字段长什么样。
## 三、参考项目 `src/core/types.ts` 的保留与删除
| 处理 | 内容 |
|---|---|
| 改写后保留 | `Json`、`Measurement`、`Direction`、`MetricDefinition` 与两档"测不到时怎么办"、`ModelUsage`、`RunResult` 里的启动状态和资源用量、`canonical`、`hash`、运行定义里"镜像按 sha256 钉死、运行时写明、不继承宿主环境变量"这几条 |
| 删除 | `Lease`、`StudyStatus`(改用文件锁;进度从账本现算) |
| 删除 | 观测量表、观测量四组、`HardRule`、`validateObservable*`、`validateObservationSet`、`hardRuleVerdict`(不再用模型审查观测量;硬规则校验以后放进 tasks 内部) |
| 删除 | `comparisonConditionsHash`、`scoreConditionsHash`,以及为它们分出的两块环境变量 |
| 删除 | `assert`、`finite`、`positiveInteger`、`nonempty`、`identifier`、`validateManifest`、`validateMetric`、`validateRound`、`validateLimits`、`thresholds`(改用 TypeBox 字段定义检查) |
| 删除 | `Thresholds`、`StudyLimits`、`ComputeLimits`、`processEnvironment`、`collectedMetrics`、`worstCaseCost`、`RoundDefinition`、`SYNERGY_LABELS`(都只有一个模块用,等写那个模块时放进去) |
| 不搬 | 注释里的修改历史和"参考项目以前怎样"的说明。注释只写现在 |
`assertNever` 这类只有一两行的类型辅助,如果几个模块确实都要用,可以放进来,但要先说清楚哪几个模块会用它。
## 四、测试
- vocab 基本没有逻辑,字段定义不写逐字段的测试。
- 规范序列化和哈希各写测试。预期值要独立得到,不能拿实现算出来的结果当预期值:
- 规范序列化的预期字符串,自己手写;
- 哈希的预期值,用命令行的 `sha256sum` 算。
- 至少覆盖这几种情况:键的顺序不同,结果相同;嵌套数组;遇到 NaN 或 Infinity 报错;遇到带自定义原型的对象报错。
- 每种提交挑一份合法的样例,确认能通过字段定义的检查。这一步也是在检查字段写得是不是方法.md 第五部分的意思。
## 五、完成后要更新的文档
- `docs/结构.md` 第八部分:补上 vocab 对外的类型、名单和两个函数,每项一句话。
- `WORK_LOG.md`:按它的格式更新当前状态。
- 不新建其他 md 文件。
## 六、验收与报告
做完后本地提交,然后在回复里交一份报告,监督者会对着实际文件逐项核对:
1. 提交号,新增文件列表,每个文件的行数,vocab 的总行数。
2. `npm run check` 和 `npm test` 的完整输出。
3. 临时违规引用时 `npm run check` 的报错输出(见第一部分最后一条)。
4. 你和这份任务书或方法.md 不一致的地方,以及为什么。
5. **规则不清楚的地方**:读 CLAUDE.md、结构.md、方法.md 时,哪里让你犹豫、哪里两份文件说法不一致、哪里你是靠猜的。这一条对这次任务特别重要,没有就写"没有"。