@mcptoolshop/research-os 0.3.1 → 0.3.2

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.
package/README.zh.md CHANGED
@@ -7,7 +7,7 @@
7
7
  </p>
8
8
 
9
9
  <p align="center">
10
- <a href="https://github.com/mcp-tool-shop-org/research-os/releases/tag/v0.1.0"><img src="https://img.shields.io/badge/version-0.1.0-blue" alt="version 0.1.0"></a>
10
+ <a href="https://github.com/mcp-tool-shop-org/research-os/releases/tag/v0.3.2"><img src="https://img.shields.io/badge/version-0.3.2-blue" alt="version 0.3.2"></a>
11
11
  <a href="https://github.com/mcp-tool-shop-org/research-os/actions/workflows/ci.yml"><img src="https://github.com/mcp-tool-shop-org/research-os/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
12
12
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="MIT License"></a>
13
13
  <img src="https://img.shields.io/badge/node-%E2%89%A520-brightgreen" alt="Node ≥20">
@@ -16,77 +16,34 @@
16
16
 
17
17
  # research-os
18
18
 
19
- `research-os` 是一个本地优先的命令行工具,它将一个开放性的主题转化为一个结构化的**研究包**,在这个结构化的代码仓库中,Claude、Cowork或其他系统可以工作数小时,而不会出现幻觉或偏离研究方向。
19
+ `research-os` 是一个本地优先的命令行工具,它将一个开放式的主题转化为一个结构化的 **研究包**,在这个结构化的代码仓库中,Claude、Cowork 或其他工具可以在不产生幻觉或歪曲研究结果的情况下工作数小时。
20
20
 
21
21
  ## 它是什么
22
22
 
23
- `research-os` 是“我想研究 X”和“一个经过验证、可追溯证据的基础”之间的控制层。它将发现线索与获取证据、原始提取与筛选后的论点、矛盾检测与矛盾解决、审查决策与综合结论等环节分开。每个步骤都会写入一个只追加的日志;每个准备就绪的判断都是基于这些日志计算得出的,而不是主观臆断。
23
+ `research-os` 是“我想研究 X”和“一个经过验证、可追溯证据的基础”之间的控制层。它将发现线索与获取证据分离,将原始提取与筛选后的主张分离,将矛盾检测与矛盾解决分离,并将审查决策与综合结果分离。每个步骤都会写入一个只追加的日志;每个就绪的判断都是基于这些日志计算得出,而不是主观声明。
24
24
 
25
- 它不是一个报告生成器。它不是一个大型语言模型(LLM)编排的**框架**。它不会为你自动生成综合结论。它强制执行在开始综合之前必须满足的条件。
25
+ 它不是一个报告生成器。它不是一个 LLM 编排的框架。它不会为你编写综合报告。它强制执行综合分析开始的条件。
26
26
 
27
- **v0.1 版本** 仅被使用过一次:它本身被用于测试自身。这次测试发现了 `research-os` 中的七个正确性问题,并在本次**发布**之前都已修复。完整的验证过程——七个会话、两种集成模式、463 个 `vitest` 测试用例、一个冻结的**研究包**——都记录在 [`docs/dogfood-proof.md`](docs/dogfood-proof.md) 文件中。 详细指南:<https://mcp-tool-shop-org.github.io/research-os/handbook/>。
27
+ 已冻结的研究包被归档在 [`mcp-tool-shop-org/research-packs`](https://github.com/mcp-tool-shop-org/research-packs) 仓库中,其中包含两个初始版本。请参阅 [`docs/roadmap.md`](docs/roadmap.md) 以了解 v1.0 的发展路线图。
28
28
 
29
- ## 16 条核心原则
30
-
31
- | # | 原则 |
32
- |---|-----|
33
- | 1 | 在获得原始数据之前,不能进行综合。 |
34
- | 2 | 获取是证据;提取是解释。 |
35
- | 3 | 模型可以解释原始数据的片段,但不能生成证据片段。 |
36
- | 4 | 提取可能会产生过多的信息;综合不能简单地继承这些信息。 |
37
- | 5 | 矛盾映射会暴露潜在的冲突,但它不会解决、综合或决定哪个论点更胜一筹。 |
38
- | 6 | 闸门决定一个部分是否符合综合的条件。它们不进行综合,也不隐藏失败。 |
39
- | 7 | 对抗性审查用于评估研究的完整性。它不进行综合,也不重写原始数据。 |
40
- | 8 | 索引使研究结果可以被查询。它不创造新的事实,也不成为官方记录。 |
41
- | 9 | Cowork 模式将研究结果转化为可操作的指令。它不创造事实,也不绕过闸门。 |
42
- | 10 | 综合工作区用于组织 Cowork 模式中接受的研究结果。它不进行综合,也不绕过 Cowork 模式。 |
43
- | 11 | **研究包**审计汇总现有的研究结果。它不创造新的事实,也不隐藏部分级别的证据。 |
44
- | 12 | 发现阶段提出线索;只有获取阶段才能产生证据。 |
45
- | 13 | 只有当经过测试证明其能够准确回忆时,审查者才会被信任。 |
46
- | 14 | 论点的数量并不能代表研究的质量。在进行综合之前,必须对论点进行筛选。 |
47
- | 15 | 冻结锁定已完成的研究结果。它不完成未完成的研究,也不将修复状态转化为证据。 |
48
- | 16 | 豁免可以放宽对原始数据的限制,但不能制造证据。 |
49
-
50
- **第 3 条原则**:大型语言模型(LLM)绝不能生成证据文本。`research-os` 构建了一个确定性的摘录日志(具有稳定 ID,例如 `ex_<source_id_hex>_001`);大型语言模型选择摘录 ID;`research-os` 复制原始文本。 “释义作为引用”的错误类型在结构上是无法实现的。
51
-
52
- **第 14 条原则**:在提取和审查之间,`research-os claim triage`(论点筛选)会去重、限制每个来源的贡献,并将低价值的候选论点放入待处理队列。 论点筛选不会修改 `claims.jsonl` 文件;待处理的论点仍然保留在原始日志中。
53
-
54
- ## v0.1 的工作流程链
55
-
56
- ```
57
- discover
58
- → gather
59
- → claim extract
60
- → claim audit-density
61
- → claim triage
62
- → contradict map
63
- → contradict resolve
64
- → review
65
- → review-promote
66
- → gate
67
- → section report
68
- → audit
69
- → index build
70
- → cowork handoff
71
- → synth workspace
72
- → freeze
73
- ```
74
-
75
- 每个步骤都是一个命令行指令。每个步骤都会写入只追加的记录。没有哪个步骤会合成、解决或创建新的事实——这些不变性是被强制执行的,而不是被信任的。审查环节会接受、拒绝或要求修复候选声明;“gate”会根据审查结果计算“synthesis_eligible”(合成资格)。“freeze”(冻结)是最终的完整性锁,只有当所有层都同意时,才会标记一个包为完成。请参阅[docs/dogfood-proof.md](docs/dogfood-proof.md),了解v0.1版本的证明,该证明表明整个流程是端到端的。
76
-
77
- 这是一种替代 *搜索 → 摘要 → 精美报告* 的结构化方法。这个流程是最终产品。
29
+ v0.1 版本已经在两个内部测试阶段进行了压力测试。第一次测试——`research-os` 研究自身的规范——在 v0.1.0 发布之前发现了七个正确性问题,每个问题都需要实际的代码修复,并衍生出相应的规则或集成模式。第二次测试(v1 实验 1:ComfyUI 工作流程的稳定性,11 个会话,一个与 `research-os` 没有任何词汇重叠的领域)于 2026-05-09 结束:研究包已冻结,归档已上线,模式 2 的执行通过提交 `22b5dba` 完成。v0.1 版本的验证记录位于 [`docs/dogfood-proof.md`](docs/dogfood-proof.md);实验 1 的验证记录位于 [`docs/experiment-1-proof.md`](docs/experiment-1-proof.md)。 详细文档:<https://mcp-tool-shop-org.github.io/research-os/handbook/>。
78
30
 
79
31
  ## 安装
80
32
 
81
33
  **要求:** Node.js ≥ 20。
82
34
 
83
35
  ```bash
84
- # From source (v0.1.0 is not yet published to npm)
36
+ npm install -g @mcptoolshop/research-os
37
+ ```
38
+
39
+ 对于从源代码构建的贡献者:
40
+
41
+ ```bash
85
42
  git clone https://github.com/mcp-tool-shop-org/research-os.git
86
43
  cd research-os
87
44
  npm install
88
45
  npm run build
89
- npm link # makes `research-os` available on your PATH
46
+ npm link
90
47
  ```
91
48
 
92
49
  ## 快速开始
@@ -119,41 +76,112 @@ research-os index build --all
119
76
  research-os cowork handoff
120
77
  research-os synth workspace # only if handoff returned synthesis_ready
121
78
  research-os freeze
79
+
80
+ # Export to the research-packs archive
81
+ research-os pack publish \
82
+ --to <research-packs>/packages/<name>
122
83
  ```
123
84
 
124
- **要查看一个实际的示例,**请查看 `research-os-packs/research-os-spec/` 目录下的“dogfood”包——每个记录、每个凭证、每个处理结果、每个冻结指纹,都存储在只追加的日志文件中。该包生成了 `docs/dogfood-proof.md`。
85
+ **要查看一个实际的示例**,请参阅 `research-os-packs/research-os-spec/` 目录下的研究包——每个文件、每个记录、每个结论、每个冻结的指纹,都以只追加的日志形式存储在磁盘上。该研究包生成了 `docs/dogfood-proof.md`。
86
+
87
+ **需要本地运行 [ollama-intern-mcp](https://github.com/mcp-tool-shop-org/ollama-intern-mcp)**,用于 LLM 的提取、筛选、审查和发现。默认模型是 `hermes3:8b`;可以使用 `OLLAMA_INTERN_MODEL=<model>` 进行覆盖。如果 Ollama 不在默认的 `localhost:11434` 地址上,请设置 `OLLAMA_HOST`。
125
88
 
126
- **需要本地运行 [ollama-intern-mcp](https://github.com/mcp-tool-shop-org/ollama-intern-mcp)**,用于LLM提取、分诊、审查和发现。默认模型是 `hermes3:8b`;可以使用 `OLLAMA_INTERN_MODEL=<模型>` 来覆盖。如果Ollama没有安装在默认的 `localhost:11434` 上,请设置 `OLLAMA_HOST`。
89
+ ## 16 条核心规则
127
90
 
128
- ## 词汇表
91
+ | # | 规则 |
92
+ |---|-----|
93
+ | 1 | 在获得原始数据之前,不能进行综合分析。 |
94
+ | 2 | 获取是证据;提取是解释。 |
95
+ | 3 | 模型可以解释原始数据,但不能生成证据。 |
96
+ | 4 | 提取可能会产生过多的信息;综合分析不能继承这种过剩。 |
97
+ | 5 | 矛盾映射会暴露潜在的冲突,但它不会解决、综合或决定哪个主张是正确的。 |
98
+ | 6 | 网关决定一个部分是否符合综合分析的条件。它们既不进行综合分析,也不隐藏失败。 |
99
+ | 7 | 对抗性审查用于评估研究的完整性。它既不进行综合分析,也不重写原始数据。 |
100
+ | 8 | 索引可以使研究结果可查询。它既不创建新的事实,也不成为原始记录。 |
101
+ | 9 | Cowork 协作模式将研究结果转化为可操作的指令。它既不创建事实,也不绕过网关。 |
102
+ | 10 | 综合分析工作区用于组织 Cowork 协作模式中接受的研究结果。它既不进行综合分析,也不绕过协作模式。 |
103
+ | 11 | 研究包审计汇总现有的研究结果。它既不创建新的事实,也不隐藏部分级别的证据。 |
104
+ | 12 | 发现阶段提出线索;只有获取才能产生证据。 |
105
+ | 13 | 只有在经过多次失败测试证明其可回溯性后,才能信任审查者。 |
106
+ | 14 | 声称拥有大量信息并不代表研究质量。在进行综合分析之前,必须对这些信息进行筛选。 |
107
+ | 15 | “冻结”状态锁定已完成的研究成果,但不会完成未完成的研究,也不会将修复状态转化为证据。 |
108
+ | 16 | 豁免可以放宽对来源的限制,但不能用于伪造证据。 |
109
+
110
+ **第三条规则**:大型语言模型(LLM)绝不会生成证据文本。`research-os` 构建一个确定性的摘录记录(具有稳定 ID,例如 `ex_<source_id_hex>_001`);LLM 选择摘录 ID;`research-os` 复制原始文本。 “释义作为引用”的错误类型在结构上是无法实现的。
111
+
112
+ **第十四条规则**:在提取和审查阶段,`research-os claim triage`(研究主张筛选)会去除重复项,限制每个来源的贡献,并将低价值的主张放入待处理队列。筛选过程不会修改 `claims.jsonl` 文件;待处理的主张仍然保留在原始记录中。
113
+
114
+ ## v0.1 工作流程链
115
+
116
+ ```
117
+ discover
118
+ → gather
119
+ → claim extract
120
+ → claim audit-density
121
+ → claim triage
122
+ → contradict map
123
+ → contradict resolve
124
+ → review
125
+ → review-promote
126
+ → gate
127
+ → section report
128
+ → audit
129
+ → index build
130
+ → cowork handoff
131
+ → synth workspace
132
+ → freeze
133
+ ```
134
+
135
+ 每个步骤都是一个命令行指令。每个步骤都会写入只追加的记录文件。任何步骤都不会进行综合、解决或创建新的真理——这些原则是强制执行的,而不是被信任的。审查人员可以接受、拒绝或要求修复候选主张;“门禁”系统会根据审查结果计算 `synthesis_eligible`(是否符合综合条件);“冻结”是最终的完整性锁定,只有当所有层级都同意时,才会标记一个项目为已完成。请参阅 [docs/dogfood-proof.md](docs/dogfood-proof.md),了解 v0.1 的完整证明,该证明表明整个链条是端到端的。
136
+
137
+ 这是 *搜索 → 总结 → 生成报告* 的结构性替代方案。整个链条是最终产品。
138
+
139
+ ## 术语
129
140
 
130
141
  | 术语 | 含义 |
131
142
  |------|---------|
132
- | `research-os` | 控制平面 / 命令行 / 闸门 / 编排规则 (此仓库) |
133
- | `research-pack` | 用于一个研究项目的生成的仓库记录 |
134
- | `research section` | 在某个包内部的有限的调查单元 |
135
- | `research receipt` | 证明某个部分通过了源/声明/闸门检查 |
143
+ | `research-os` | 控制平面 / 命令行 / 门禁 / 编排规则(此仓库) |
144
+ | `research-pack` | 用于单个研究项目的生成仓库文件 |
145
+ | `research section` | 在项目中,一个受限的调查单元 |
146
+ | `research receipt` | 证明某个部分通过了来源/主张/门禁检查 |
136
147
 
137
148
  ## 安全性
138
149
 
139
- `research-os` 是一个本地优先的命令行工具。它在您指定的 research-pack 目录下读取和写入文件,并在使用 `gather` 命令时,会向您提供的源 URL 发送 HTTP 请求。它不会:运行服务器、接受入站连接、存储凭据或发送遥测数据。任何敏感信息都不会写入到包的记录中。请参阅 [SECURITY.md](SECURITY.md),了解漏洞报告政策。
150
+ `research-os` 是一个本地优先的命令行工具。它在您指定的“研究包”目录中读取和写入文件,并在使用 `gather` 命令时,会向外部发送 HTTP 请求以获取您提供的来源 URL。它不会:运行服务器、接受传入连接、存储凭据或发送遥测数据。任何敏感信息都不会写入到包文件中。请参阅 [SECURITY.md](SECURITY.md),了解漏洞报告政策。
140
151
 
141
152
  ## 状态
142
153
 
143
- **v0.1.0** — 冻结于 2026-05-08。`research-os-packs/research-os-spec/` (兄弟仓库) 中的“dogfood”包已完成冻结,共接受了 8 个部分中的 296 个声明,17 个已处理,30 个被操作员覆盖,0 个活动修复阻塞,0 个未解决的矛盾,所有闸门 `synthesis_eligible=true`。463/463 个 vitest 测试通过。共有 16 条关键规则。请参阅 [`docs/dogfood-proof.md`](docs/dogfood-proof.md),了解 7 个发现和冻结凭证指纹。
154
+ **v0.3.2** — 已发布到 npm,版本号为 `@mcptoolshop/research-os@0.3.2`,发布日期为 2026年5月9日。该版本对已接受的声明进行了标准化处理,考虑了 `pack publish` 的准入情况。 严格的 `claim-reviews.jsonl` 文件与 `pack-audit.json::accepted_claims` 之间的相等性检查已被替换为集合比较——已接受的声明是具有唯一 `claim_id`,且其最新的规范审查决定为 `accepted_for_synthesis`(每个 `claim_id`,最新决定优先)。 对于那些其历史审计计数与集合比较结果不同的已冻结的包,现在会发出警告而不是拒绝; 原始的审计文件将被完整保留(第15条),而归档清单会反映标准化后的计数。 对于虚构的 `claim_id`、不兼容的重复决策以及不符合合成条件的场景,仍然会拒绝。 这是通过实验 3 XRPL pack Session K 获得的,该实验在实际的账本边界不一致时,`pack publish` 被拒绝(第07部分有24行原始的 `accepted_for_synthesis` 数据,但由于审查员窗口的重叠,只有19个唯一的 `claim_id`)。 558/558 个 vitest 测试通过。 详情请参阅 [CHANGELOG.md](CHANGELOG.md) [`docs/pack-publish.md`](docs/pack-publish.md)
155
+
156
+ **v0.3.1** — 已发布到 npm,版本号为 `@mcptoolshop/research-os@0.3.1`,发布日期:2026-05-09。 包含按章节划分的来源豁免 (`primary_source_waiver.section_waivers[]`),以及审查人员的确认,因此,如果某个章节的“来源垄断”被豁免,则该豁免会成为一个可见的提示,而不是自动将所有主张都标记为“需要修复来源”。 这是通过实验 3 XRPL 包的第二阶段实现的——针对“标准协议”部分的分析(包括单链、封闭式 API 规范和标准机构文档)推翻了“发布者多样性是衡量真理质量的指标”的假设。 540/540 个 vitest 测试通过。 请参阅 [CHANGELOG.md](CHANGELOG.md) 和 [`docs/section-scoped-waivers.md`](docs/section-scoped-waivers.md)。
157
+
158
+ **按章节划分的来源豁免**:当发布者多样性与该章节的真理来源结构上不兼容时,才使用这些豁免,而不是仅仅因为某个章节未能找到足够的来源。 豁免必须包含经过模式验证的 `reason`(原因)以及非空 `compensating_controls[]`(补偿控制)。 包策略 `primary_source_waiver_allowed: false` 会阻止包级别和章节级别的豁免。 之前的 v0.3.1 版本中,包级别的 `min_independent_publishers: 0` 是一种解决方法,现在已弃用;现有的已冻结的包仍然在现有记录下有效。 请参阅 [`docs/section-scoped-waivers.md`](docs/section-scoped-waivers.md) 和 [research-packs 操作手册](https://github.com/mcp-tool-shop-org/research-packs/blob/main/docs/operator-playbook.md)。
159
+
160
+ **v0.3.0** — 发布于 2026-05-09。 针对 `contradict map`,发布了 `--detector <auto|heuristic|ollama-intern>` 标志(来自 Experiment 3 Session 1,XRPL pack 的 F-09 chain-blocker 修复)。 此时,527/527 个 vitest 测试通过。 检测器的选择现在是明确的操作员选择,而不是依赖于状态的环境变量;模式会在每次运行时显式显示。 参见 [`docs/contradict-map.md`](docs/contradict-map.md)。
161
+
162
+ **v0.2.0** — 发布于 2026-05-09。 发布了 `research-os pack publish`(Experiment 2)以及 Pattern 2 的就绪谓词修复。 此时,515/515 个 vitest 测试通过。 参见 [CHANGELOG.md](CHANGELOG.md)。 冻结的软件包导出到标准的 `research-packs` 归档,只需一个命令即可完成; 许可协议由代码强制执行,而不是检查清单。 参见 [`docs/pack-publish.md`](docs/pack-publish.md)。
163
+
164
+ **v0.1.0** — 2026-05-08 冻结了内部测试软件包。 位于 `research-os-packs/research-os-spec/`(兄弟仓库)的软件包已冻结,共包含 8 个部分,有 296 个已接受的声明,17 个已处理,30 个被操作员覆盖,0 个活动修复阻止器,0 个未解决的矛盾,所有条件 `synthesis_eligible=true`。 共有 16 条关键规则。 参见 [`docs/dogfood-proof.md`](docs/dogfood-proof.md),其中包含七个发现和冻结确认的指纹。
165
+
166
+ **research-packs 归档单库** — 位于 [`mcp-tool-shop-org/research-packs`](https://github.com/mcp-tool-shop-org/research-packs),包含两个初始软件包。 `comfyui-workflow-durability`(Experiment 1,302 个已接受的声明,8 个部分)和 `research-os-self-dogfood`(v0.1 内部测试回填,296 个已接受的声明,8 个部分)。 这两个软件包都通过了 `verify-pack.mjs` 测试。
167
+
168
+ **v1 Experiment 1 (ComfyUI 工作流程的稳定性)** — 已于 2026-05-09 结束。 终端 A 的所有 8 个部分已完成,软件包已冻结,归档已上线。 参见 [`docs/experiment-1-proof.md`](docs/experiment-1-proof.md) 和 [`docs/roadmap.md`](docs/roadmap.md)。
169
+
170
+ ### v0.3 的局限性
171
+
172
+ - 尚未经过外部用户的实际测试。 两个内部测试阶段已结束,一个为自指代,一个为外部领域,实验 3(在外部压力下的 API 稳定性)正在进行中:3个包中的第2个包(XRPL 创建者令牌的持久性)已冻结,包含来自 7 个部分的总计 251 个已接受的声明,等待通过 npm v0.3.2 的 `pack publish` 准入。 该阶段已经获得了 v0.3.0 的 `--detector` 标志(F-09 链阻塞器)、v0.3.1 的部分范围的源代码豁免(F-10/F-11 规范协议压力)以及 v0.3.2 的标准化已接受声明处理(F-36 账本边界)。 还需要一个外部领域的包才能完成实验 3。
173
+ - 不是合成内容生成器。 `synth workspace` 命令用于生成结构化的工作空间; 人类(或 Cowork)根据已接受的声明 ID 编写内容。
174
+ - 在语义版本控制下,API 稳定性尚未实现。 v1.0.0 是一个需要实现的阶段,而不是一个日历日期; 详情请参阅 [`docs/roadmap.md`](docs/roadmap.md),其中列出了用于弥补差距的六个实验。
144
175
 
145
- ### v0.1 的局限性
176
+ ### 已知的局限性
146
177
 
147
- - 尚未经过外部用户的严格测试。在一次内部测试中发现了 7 bug。
148
- - 尚未发布到 npm。在 `npm publish` 之前,请从源代码安装。
149
- - 不是一个合成器。`synth workspace` 命令会生成结构化的工作区;人类(或 Cowork)会根据已接受的声明 ID 编写文本内容。
150
- - 在语义版本控制下,API 稳定性尚未确定。v1.0.0 版本将在外部用户验证了该接口之后发布。
178
+ - **提取器的来源信息在接口处不可见。** 一个部分可以满足已接受声明的最低要求,同时依赖于启发式回退声明,当经过校准的提取器(配置了模型的 Ollama)不可用时。 这已记录为路线图中的 Experiment 4; 未来的改进将报告每个提取器的已接受声明,并要求满足接口要求的已接受声明数量来自校准路径。
179
+ - **超出经过校准的 `hermes-two-pass` 基线的审查器模型选择尚未解决。** 内部测试阶段验证了一种审查器配置; 其他模型需要在它们被信任之前,进行种子失败召回校准。 这是路线图中的 Experiment 5。
180
+ - **v0.1 内部测试软件包使用了 `mistral-nemo:12b` 进行提取(标准的默认配置是 `hermes3:8b`)。** v0.1 阶段,此设备上不可用 `hermes3:8b`。 此替代方案的说明将持续有效,直到生成基于 hermes3 的确认——这是路线图中的 Experiment 6。 对于在没有 `hermes3:8b` 的设备上的操作员,请将 `OLLAMA_INTERN_MODEL` 设置为可用的模型; 操作员预配置的 URL 和查询精度规范(参见手册)可以减轻对模糊主题的幻觉。
151
181
 
152
- ### 已知限制
182
+ ## 通往 v1.0 的路线图
153
183
 
154
- - **提取器的来源信息在网关接缝处不可见。** 在校准后的提取器(配置了模型的 Ollama)不可用时,某些部分可能会通过“可接受声明”的阈值,但这依赖于启发式方法的备用方案。这被记录为已知的弱点;未来的改进将报告提取器提供的“可接受声明”数量,并要求校准路径必须达到阈值所需的“可接受声明”数量。
155
- - **关于超出校准的 `hermes-two-pass` 基准线的评审模型选择问题尚未解决。** 内部测试验证了一种评审模型配置;其他模型需要在被信任之前,进行独立的、基于预设失败情况的校准。
156
- - **内部测试使用的提取模型是 `mistral-nemo:12b`(默认配置是 `hermes3:8b`)。** 在发现过程中,系统会产生与当前主题不相关的错误结果,针对自指部分名称的问题,通过查询精度控制(参见手册)以及操作员预先设置的 URL 来进行修正,以解决模糊主题的问题。
184
+ v1.0 是一个需要达成的状态,而不是一个发布日期。在 v0.1 和 v1.0 之间,有六个正在进行的实验。这些实验包括:非自指的内部测试版本(目前正在进行中的 ComfyUI 工作流程稳定性包)、一个 `research-os pack publish` 命令,该命令可以自动将内容导出到标准的 `research-packs` 单仓库(实验 2,其范围受实验 1 的手动关闭影响)、在外部压力下的 API 稳定性、弥补提取器溯源方面的差距、将评审员校准推广到 `hermes-two-pass` 之外,以及在 `hermes3:8b` 上进行的干净基准测试。实验 1 在打包完成时尚未结束——它会在打包版本作为 `research-packs` 单仓库中的第一个软件包发布时完成,同时也会发布 v0.1 的内部测试版本补丁。完整计划请参见 [`docs/roadmap.md`](docs/roadmap.md)。整个过程中,架构保持不变;v1.0 旨在深化 v0.1 已经证明的内容,而不是重新开启新的方向。
157
185
 
158
186
  ## 许可证
159
187
 
package/dist/cli.js CHANGED
@@ -11872,7 +11872,7 @@ var init_src = __esm({
11872
11872
  init_triage();
11873
11873
  init_discover();
11874
11874
  init_errors();
11875
- RESEARCH_OS_VERSION = "0.3.1";
11875
+ RESEARCH_OS_VERSION = "0.3.2";
11876
11876
  }
11877
11877
  });
11878
11878
 
@@ -12311,12 +12311,55 @@ import { join as join31, basename, resolve as resolve24 } from "path";
12311
12311
 
12312
12312
  // src/pack/publish/manifest.ts
12313
12313
  init_schema();
12314
+ init_schema9();
12314
12315
  import { createHash as createHash11 } from "crypto";
12315
12316
  import { readFileSync, existsSync as existsSync28 } from "fs";
12316
12317
  import { join as join28 } from "path";
12317
12318
  import { parse as parseYaml } from "yaml";
12318
12319
  import { z as z23 } from "zod";
12319
12320
 
12321
+ // src/closure-ledger/effective-accepted.ts
12322
+ function getEffectiveDecisionMap(reviews) {
12323
+ const map2 = /* @__PURE__ */ new Map();
12324
+ for (const r of reviews) {
12325
+ const existing = map2.get(r.claim_id);
12326
+ if (!existing || r.created_at > existing.created_at) {
12327
+ map2.set(r.claim_id, r);
12328
+ }
12329
+ }
12330
+ return map2;
12331
+ }
12332
+ function getEffectiveAcceptedClaimIds(reviews) {
12333
+ const decisionMap = getEffectiveDecisionMap(reviews);
12334
+ const accepted = /* @__PURE__ */ new Set();
12335
+ for (const [claim_id, r] of decisionMap) {
12336
+ if (r.decision === "accepted_for_synthesis") accepted.add(claim_id);
12337
+ }
12338
+ return accepted;
12339
+ }
12340
+ function findIncompatibleDecisions(reviews) {
12341
+ const groups = /* @__PURE__ */ new Map();
12342
+ for (const r of reviews) {
12343
+ const key = `${r.claim_id}|${r.created_at}`;
12344
+ let set = groups.get(key);
12345
+ if (!set) {
12346
+ set = /* @__PURE__ */ new Set();
12347
+ groups.set(key, set);
12348
+ }
12349
+ set.add(r.decision);
12350
+ }
12351
+ const conflicts = [];
12352
+ for (const [key, decisions] of groups) {
12353
+ if (decisions.size > 1) {
12354
+ const sep3 = key.lastIndexOf("|");
12355
+ const claim_id = key.slice(0, sep3);
12356
+ const created_at = key.slice(sep3 + 1);
12357
+ conflicts.push({ claim_id, created_at, decisions: [...decisions] });
12358
+ }
12359
+ }
12360
+ return conflicts;
12361
+ }
12362
+
12320
12363
  // src/pack/publish/schema.ts
12321
12364
  import { z as z22 } from "zod";
12322
12365
  var SectionSummarySchema = z22.object({
@@ -12348,6 +12391,7 @@ var GateResultMinimalSchema = z23.object({
12348
12391
  verdict: z23.enum(["pass", "warn", "fail", "blocked"]),
12349
12392
  synthesis_eligible: z23.boolean()
12350
12393
  });
12394
+ var ClaimIdOnlySchema = z23.object({ claim_id: z23.string() });
12351
12395
  function sha256Bytes(buf) {
12352
12396
  return createHash11("sha256").update(buf).digest("hex");
12353
12397
  }
@@ -12358,11 +12402,15 @@ function readJsonlSafe(filePath) {
12358
12402
  if (!existsSync28(filePath)) return [];
12359
12403
  return parseJsonl(readFileSync(filePath, "utf8"));
12360
12404
  }
12361
- function latestClaimDecisions(reviews) {
12362
- const m = /* @__PURE__ */ new Map();
12363
- const sorted = [...reviews].sort((a, b) => a.created_at.localeCompare(b.created_at));
12364
- for (const r of sorted) m.set(r.claim_id, r.decision);
12365
- return m;
12405
+ function readClaimReviews(filePath) {
12406
+ if (!existsSync28(filePath)) return [];
12407
+ const raw = parseJsonl(readFileSync(filePath, "utf8"));
12408
+ const valid = [];
12409
+ for (const r of raw) {
12410
+ const parsed = ClaimReviewSchema.safeParse(r);
12411
+ if (parsed.success) valid.push(parsed.data);
12412
+ }
12413
+ return valid;
12366
12414
  }
12367
12415
  function latestContradictionStatuses(resolutions) {
12368
12416
  const m = /* @__PURE__ */ new Map();
@@ -12376,7 +12424,7 @@ function latestDispositionStatuses(dispositions) {
12376
12424
  for (const d of sorted) m.set(d.claim_id, "dispositioned");
12377
12425
  return m;
12378
12426
  }
12379
- function deriveManifest(packDir, packageName, operatorNotes = "") {
12427
+ function deriveManifest(packDir, packageName, operatorNotes = "", warnings = []) {
12380
12428
  const yamlPath = join28(packDir, "research.yaml");
12381
12429
  if (!existsSync28(yamlPath)) throw new Error(`research.yaml not found in ${packDir}`);
12382
12430
  const research = ResearchYamlSchema.parse(parseYaml(readFileSync(yamlPath, "utf8")));
@@ -12404,15 +12452,43 @@ function deriveManifest(packDir, packageName, operatorNotes = "") {
12404
12452
  let totalPreserved = 0;
12405
12453
  for (const sectionId of sectionIds) {
12406
12454
  const sectionDir = join28(packDir, "sections", sectionId);
12407
- const reviews = readJsonlSafe(join28(sectionDir, "claim-reviews.jsonl"));
12408
- const decisionMap = latestClaimDecisions(reviews);
12409
- const acceptedCount = [...decisionMap.values()].filter(
12410
- (d) => d === "accepted_for_synthesis"
12411
- ).length;
12455
+ const reviewsPath = join28(sectionDir, "claim-reviews.jsonl");
12456
+ const reviews = readClaimReviews(reviewsPath);
12457
+ const conflicts = findIncompatibleDecisions(reviews);
12458
+ if (conflicts.length > 0) {
12459
+ const first = conflicts[0];
12460
+ throw new Error(
12461
+ `Section ${sectionId}: claim-reviews.jsonl has incompatible decisions for claim_id=${first.claim_id} at created_at=${first.created_at} (decisions seen: ${first.decisions.join(", ")}). Latest-decision-wins tie-breaker undefined \u2014 investigate the review pipeline state.` + (conflicts.length > 1 ? ` (${conflicts.length - 1} other claim_id(s) similarly affected.)` : "")
12462
+ );
12463
+ }
12464
+ const effectiveAccepted = getEffectiveAcceptedClaimIds(reviews);
12465
+ const acceptedCount = effectiveAccepted.size;
12466
+ const claimsPath = join28(sectionDir, "claims.jsonl");
12467
+ if (existsSync28(claimsPath)) {
12468
+ const claimRows = parseJsonl(readFileSync(claimsPath, "utf8"));
12469
+ const claimIds = /* @__PURE__ */ new Set();
12470
+ for (const c of claimRows) {
12471
+ const parsed = ClaimIdOnlySchema.safeParse(c);
12472
+ if (parsed.success) claimIds.add(parsed.data.claim_id);
12473
+ }
12474
+ const phantoms = [];
12475
+ for (const cid of effectiveAccepted) {
12476
+ if (!claimIds.has(cid)) phantoms.push(cid);
12477
+ }
12478
+ if (phantoms.length > 0) {
12479
+ throw new Error(
12480
+ `Section ${sectionId}: ${phantoms.length} effective accepted claim_id(s) absent from claims.jsonl \u2014 phantom claims violate the closure-ledger subset invariant. Examples: ${phantoms.slice(0, 3).join(", ")}` + (phantoms.length > 3 ? ` (+${phantoms.length - 3} more)` : "")
12481
+ );
12482
+ }
12483
+ } else {
12484
+ warnings.push(
12485
+ `section ${sectionId}: claims.jsonl absent \u2014 phantom-claim integrity check skipped`
12486
+ );
12487
+ }
12412
12488
  const auditAccepted = auditSectionMap.get(sectionId);
12413
12489
  if (auditAccepted !== void 0 && auditAccepted !== acceptedCount) {
12414
- throw new Error(
12415
- `Section ${sectionId}: accepted_claims mismatch between claim-reviews.jsonl (${acceptedCount}) and pack-audit.json (${auditAccepted}). Closure-ledger seam disagreement \u2014 investigate before publishing.`
12490
+ warnings.push(
12491
+ `section ${sectionId}: legacy pack-audit.json accepted_claims (${auditAccepted}) differs from effective accepted set (${acceptedCount}). Using effective count (${acceptedCount}) in manifest. Legacy audit count preserved in pack/audits/pack-audit.json (immutable per Law 15).`
12416
12492
  );
12417
12493
  }
12418
12494
  const gateResultPath = join28(packDir, "audits", `${sectionId}-gate.json`);
@@ -12422,6 +12498,11 @@ function deriveManifest(packDir, packageName, operatorNotes = "") {
12422
12498
  const gateResult = GateResultMinimalSchema.parse(
12423
12499
  JSON.parse(readFileSync(gateResultPath, "utf8"))
12424
12500
  );
12501
+ if (!gateResult.synthesis_eligible) {
12502
+ throw new Error(
12503
+ `Section ${sectionId}: gate is not synthesis_eligible (verdict=${gateResult.verdict}). Pack admission requires every section to be synthesis-eligible.`
12504
+ );
12505
+ }
12425
12506
  const dispositions = readJsonlSafe(
12426
12507
  join28(sectionDir, "claim-synthesis-dispositions.jsonl")
12427
12508
  );
@@ -12730,7 +12811,7 @@ async function publish(input) {
12730
12811
  );
12731
12812
  }
12732
12813
  }
12733
- const manifest = deriveManifest(fromDir, packageName, input.operatorNotes ?? "");
12814
+ const manifest = deriveManifest(fromDir, packageName, input.operatorNotes ?? "", warnings);
12734
12815
  if (input.dryRun) {
12735
12816
  const finalReportPath2 = join31(fromDir, "synthesis/final-report.md");
12736
12817
  const finalReport2 = existsSync30(finalReportPath2) ? readFileSync3(finalReportPath2, "utf8") : "";