muse-agent-example/docs/2026-07-20-正文智能体正式优化设计与计划.md

518 lines
52 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.

# 正文智能体正式优化设计与计划
> 状态:评审修订版;Gate A 尚未 real-run
> 日期:2026-07-20
> 定位:本文是实验台“正文智能体正式优化”的任务 SoT;稳定概念仍以父仓 `design-docs/` 为准。Gate B 通过后才回填架构-04、专题-01/03/04/05/06/07、相关 API 契约、schema 和索引,本文完成蒸馏后删除。
> 历史:`2026-07-16-批9c-收官与优化方案.md` 的 run1-run3 只作实验记录。
> 可视化:[正文智能体架构图](2026-07-20-正文智能体正式优化架构.html)
## 1. 意图与双流程
核心原则:**卡是索引,根据卡去读原文。** 卡负责定位实体、状态、规则和历史章节;原文负责人物声音、动作习惯、能力表现和叙事质感。卡不能替代原文,原文也不能替代正式设定与状态。
这里必须区分两个顺序:
- **能力验证顺序**:正文智能体 -> 细纲智能体 -> 大纲+设定智能体,自底向上隔离变量。
- **正式创作数据流**:大纲+设定 -> 细纲 -> 正文,自顶向下提供输入。
本任务只优化正文层。细纲与大纲+设定的真实能力验收,必须等正文层通过跨作品多样本门禁后再启动。
## 2. 目标与边界
### 2.1 目标
1. 卡检索必须带出历史来源指针,并触发原文回读。
2. 已有事实、人物声音和叙事质感分别有可追溯证据,不再靠 writer 自由猜测。
3. writer 保留真实创作空间,但不得改变细纲硬事件、结果方向和伏笔动作。
4. 生产链在交付候选前挡住可机械验证的硬错误;文学质量由独立 judge 评估,不由 detector 凭观感阻断。
5. Gate B 通过后,生成候选才进入“接受/修改后合并/丢弃”三决策,采纳后成为 Canonical 正文并触发章后抽取。
6. 多章节、多作品、多场景验证,报告假阴、假阳和无卡实体影响。
### 2.2 可信边界
- writer、semantic detector、blind judge 都由可信编排器启动为独立模型进程;模型进程只接收各自严格合同,不直接读文件、数据库或共享运行目录。
- 检索节点是唯一取数入口,负责授权、冻结、排序、预算、哈希和来源回显。
- 回放时卡与原文都只能使用 `chapter <= as_of` 的事实;目标章、未来章和标准答案不得进入 writer 进程。
- 卡的终态摘要、未来弧线和无法证明章号的字段不进入回放 `stateAsOf`。
- 长原文片段和候选正文只存在于本次受控临时数据区,不进入 git、长期报告、知识卡、日志或评测安全摘要。
### 2.3 不做
- 不由正文智能体生成或修改大纲、细纲、设定和知识卡。
- 不把双盲 judge 设为每次续写的固定在线成本;它属于离线评测或可选质量详情。
- 不在正文层自动补齐关键新角色卡;只输出设定层缺口。
- 不允许诊断实验 A/B 臂的候选进入 Canonical 接受链路。
## 3. 两条独立链路
### 3.1 产品化生产链(Gate B 后第二阶段)
```mermaid
flowchart LR
F[已确认细纲] --> RP[检索规划]
RP --> CI[卡索引与 stateAsOf]
CI --> PR[按来源指针回读原文]
PR --> EG[证据包与覆盖门]
EG --> W[无工具 writer]
W -->|补证请求且预算可用| RP
W --> D[detector 硬门]
D -->|阻塞且返修未满2轮| W
D -->|通过| S[Shadow 候选展示]
D -->|满2轮仍阻塞| H[停止并交用户]
S --> U{用户三决策}
U -->|原样接受| AP[接受前置校验]
U -->|修改后合并| M[编辑并生成 candidateVersion+1]
M --> D
AP --> C[confirm -> Canonical 正文]
U -->|丢弃| X[关闭候选]
C --> E[异步章后抽取]
E --> K[知识草稿与冲突队列]
```
本链是 Gate B=`passed` 后的产品化第二阶段,不属于 Gate A/B 前置实现范围。生产链不强制运行双盲 judge;用户可请求质量详情,或系统按抽样策略运行单次 judge,但 detector 硬门与用户三决策始终存在。
### 3.2 离线评测链
```mermaid
flowchart LR
P[预注册样本/冻结点] --> O[可信编排器<br/>授权·预算·文件 CAS]
O --> SCH[全评测集顺序表<br/>位置计数差不超过 1]
SCH --> A[A 通用原文检索<br/>不用卡]
SCH --> C[C 卡索引原文检索<br/>卡不进 Writer]
SCH --> B[B card-only<br/>诊断负对照]
A --> W[隔离 Writer 进程<br/>stdin + 严格 JSON schema]
C --> W
B --> W
W --> D[隔离 Semantic Detector 进程<br/>真实报告计算指标]
O --> T[Evaluator-only OracleTruthPack<br/>与臂无关·不进 Writer]
D --> J1[隔离 Blind Judge 进程 1]
D --> J2[隔离 Blind Judge 进程 2/反序]
T --> J1
T --> J2
J1 --> JV{双评报告均合法?}
J2 --> JV
JV -->|否| F[失败关闭]
JV -->|是| ST{评分稳定?}
ST -->|是| R[去盲汇总与归因]
ST -->|否| J3[隔离 Blind Judge 进程 3<br/>最多一次]
J3 --> J3V{报告合法且形成稳定配对?}
T --> J3
J3V -->|是| R
J3V -->|否| F
R --> GB[唯一 GateInputBuilder<br/>manifest + receipts]
GB --> G{Gate 裁决}
O -.仅编排器可写.-> V["/private/tmp raw vault<br/>目录 0700·文件 0600"]
O --> S[安全摘要与原子结果]
W -->|任一调用失败| F
D -->|任一调用失败| F
```
Gate 核心比较只有 A 与 C:A 不使用卡,以统一查询做通用历史原文检索;C 只用卡定位历史章节,再回读原文。两臂向 writer 提供完全相同的事实约束和原文字符预算,writer 都看不到卡摘要、里程碑语义或检索轨迹,因此 C-A 只能归因于“卡索引是否改善原文选择”。B 保留为 `card_only_diagnostic` 负对照,候选永不进入接受链路,也不参与 Gate B 通过阈值。
A/B/C 都使用 `mode=diagnostic_only`、`acceptanceEligible=false`;Gate 通过只形成离线证据,任何臂都不能直接进入产品接受链路。
## 4. 细纲、创作自由与硬约束
细纲不是分镜脚本,需拆为两类:
| 类型 | writer 权限 |
|---|---|
| 硬事件、结果方向、伏笔动作、章末钩子、必须出场实体 | 不得删除、反转或提前回收 |
| 场景切分、局部顺序、过渡方式、环境质感、动作和对白细节 | 可合并、拆分或局部调序 |
writer 可以创造非 Canonical 的环境细节、动作、过渡、无名配角和对白表达。新增地名、能力、组织、人物身份、代际、战绩或关系等 Canonical 事实,必须进入“新设定申报”,不得直接写成已确认事实。
补证请求不是固定一次,而是受总预算控制:最多 3 次请求、累计新增上下文不超过本次检索预算的 30%;任一上限达到后停止补证并报告缺口。
## 5. 两阶段检索
### 5.1 检索规划
查询来自细纲硬约束与可调整节拍,包括人物、关系、地点、物品、能力、力量规则、历史回调、伏笔、语言指纹和同类历史场景。
`RetrievalPlan` 必须固定。`runId` 是运行元数据,不参与计划身份;`planId` 使用下表除 `runId` 外字段的规范 JSON 计算 SHA-256:UTF-8、NFC、LF 换行、对象键排序、数组保持合同顺序、无额外空白。
| 字段 | 含义 |
|---|---|
| `planVersion/runId/asOf` | 合同版本、运行 ID、冻结点;runId 不进入 planId |
| `queries[]` | `queryId`、查询文本、实体类型、检索目的、topK |
| `cardIndexVersion` | 卡索引和嵌入模型版本 |
| `proseIndexVersion` | 原文索引/读取器版本 |
| `filters` | 作品、授权、章号上限、来源状态 |
| `tieBreak` | `score DESC, sourceVersion ASC, sourceId ASC, offset ASC` |
| `tokenBudget` | 卡、连续原文、历史证据、范式各自预算 |
### 5.2 卡索引与冻结
每个卡命中返回:`cardId/name/type/retrievalReason/sourceRefs/stateAsOf`。
`stateAsOf` 只能由绝对章号 `<= as_of` 的里程碑重建。以下字段直接排除或阻断:
- 全书终态摘要;
- 未来成长弧线与结局方向;
- 无法证明绝对章号的演变事实;
- 内容描述明显属于目标章或未来章的错位里程碑。
正向创作没有回放冻结点时,`asOf` 等于当前 Canonical 最新章。
离线 eval_draft 的卡只在 C 臂检索器内部用于定位 `sourceRefs`,不得进入 A/C 的 WriterContext。B 负对照若保留 `indexHints`,`content` 只允许卡名、类型和实际回读章号,不得透传里程碑台阶。这个收紧只作用于离线诊断,生产 Canonical 卡继续使用既有冻结状态提示。
### 5.3 根据卡回读原文
首版必须保留 run3 已验证条件:**目标章之前连续 4 章全文**。选择性裁剪只能作为后续 A/B 实验变量;未证明不降质前,不得替代四章全文基线。
在连续四章之外,按卡来源指针补充:
1. 最近一次状态变化场景;
2. 人物代表性语言场景;
3. 能力、物品或关系的代表性表现;
4. 与本章细纲同类的历史场景。
若 eval_draft 卡没有持久化 `sourceRefs`,C 臂可把冻结线内最近三个里程碑章作为检索候选来源,但送入 writer 的仍只能是回读后的 Canonical 原文。该来源在 manifest 标记 `sourceRef.sourceType=card_chapter_proxy`,不能伪装成精确片段;每个代理章原文必须出现卡规范名或预注册合法别名,否则失败关闭。连续四章基线不可裁剪,A/C 选择性原文统一按同一 `proseCharBudget` 装配。
A/C 的 `proseCharBudget`、连续四章基线和规范化字符算法完全相同。除连续基线外,两臂都必须恰好装配预注册字符数;任一臂合格来源不足即样本失败,不得缩小一臂预算迁就另一臂。检索策略和完整 manifest 只留在编排器侧,不送入 writer。A/C WriterContext 的 allowlist diff 只允许所选原文 `sourceRefs/hash/content` 及其派生的上下文 hash 不同;事实约束、细纲、执行配置、篇幅合同和所有其他字段必须逐字节相同。
`RetrievalManifest` 保存 `planId`、查询、过滤、排序、来源版本、章号、片段 offset、内容哈希和裁剪原因。`manifestId` 对规范化来源集合计算 SHA-256,排除 `runId`、时间戳和执行节点;同一 `planId` 与索引版本必须产生相同 `manifestId`。
## 6. 双证据模型
### 6.1 事实证据 `factEvidence`
负责“写得对”。可信来源包括:
- 已确认设定;
- Canonical 卡与状态台账;
- 已确认历史正文;
- 细纲明确声明的本章新 Canonical 事实。
正式设定无需历史正文即可成为硬事实。抽取卡若没有可靠来源或与 Canonical 冲突,则不能单独支撑事实。
### 6.2 表现证据 `proseEvidence`
负责“写得像”。来源是历史原文场景,用于人物声音、动作习惯、战斗表现、段落节奏和章末钩子。新角色没有历史原文时不构成事实阻断,但必须使用设定/细纲约束,并降低“文风复现”置信度。
### 6.3 覆盖状态
| 状态 | 含义 | 生产处理 |
|---|---|---|
| `supported` | 事实证据充分;需要表现复现时也有原文证据 | 允许 |
| `declared_new` | 细纲/设定明确声明的新 Canonical 事实 | 允许并申报 |
| `card_gap` | 原文或正式设定可证,但缺卡 | 允许,输出卡质量问题 |
| `style_gap` | 事实可证,但没有历史表现样本 | 允许,降低风格置信度 |
| `unsupported` | 没有可信事实证据 | 阻断硬事实 |
| `conflict` | 卡、设定、状态或原文互相冲突 | 阻断并交用户 |
## 7. 可执行数据合同
### 7.1 `WriterContext v1`
| 字段 | 类型 | 必填 | 约束 |
|---|---|:---:|---|
| `schemaVersion` | string | 是 | 固定 `writer-context-v1` |
| `runId/attempt` | string/int | 是 | runId 格式受限;attempt 单调递增 |
| `mode` | enum | 是 | `production` / `diagnostic_only` |
| `qualityPolicyVersion` | string | 是 | 绑定生产或离线状态机 |
| `workId/targetChapter/asOf` | int | 是 | `asOf < targetChapter`(回放) |
| `contextSnapshot` | object | 是 | manifest ID、SHA-256、生成时间不进入哈希 |
| `sourceVersion` | string | 是 | 原始来源版本 |
| `authorizationSnapshot` | object | 是 | 不可变授权 ID、用途、重验时间 |
| `sourceStatus` | enum | 是 | 非允许状态失败关闭 |
| `retrievalPlan/manifest` | object | 是 | 产品上下文为完整检索信息;A/C 离线 writer 仅保留中性的原文 sourceRefs/hash,不含检索策略、卡命中或卡来源 |
| `fineOutline` | object | 是 | 硬约束、可调整节拍、新设定声明 |
| `narrativeState` | object | 是 | 时间、地点、角色位置、即时局面 |
| `factEvidence[]` | array | 是 | 事实 ID、来源类型、sourceRef、hash |
| `proseEvidence[]` | array | 是 | 章号、offset、hash、用途、临时片段 |
| `indexHints[]` | array | 否 | 仅 B 负对照可用;A/C 和产品生产上下文硬拒绝 |
| `evidenceStrategy` | enum | 否 | 产品生产缺省为 `production_dual_evidence`;离线三臂必须显式记录策略 |
| `patternReferences[]` | array | 否 | 已授权范式卡,只作结构方法参考 |
| `evidenceCoverage[]` | array | 是 | 细纲要素到证据的覆盖状态 |
| `outputContract` | object | 是 | 篇幅、场景、frontmatter、申报规则 |
| `tokenBudget/omittedSources` | object/array | 是 | 预算与排除原因回显 |
所有对象使用严格 schema,额外字段失败;引用的 ID、版本和 hash 必须存在且一致。
Gate A 的公共控制还固定 `selectorVersion`、选择器规范 JSON 原始字节 SHA-256、`writerInputProvenance=preregistered_fine_outline`、`oracleInputProvenance=oracle_reference_scaffold` 和 `maxContextChars=140000`。loader 在任何数据库读取前核对并原样沿用,不得按真实输入扩大预算;若固定预算连细纲硬约束和连续四章全文基线都装不下,assembler 必须失败关闭。
`evidenceStrategy` 是编排器侧字段:产品生产上下文未填写时按 `production_dual_evidence` 校验;离线 A/B/C manifest 必须分别填写 `generic_prose_retrieval`、`card_only_diagnostic`、`card_indexed_prose_retrieval`。A/C WriterContext 不携带该字段,都必须有相同 `proseCharBudget`、统一 `factEvidence` 且 `indexHints=[]`;这些事实约束只能来自正式设定、细纲声明和独立于被测卡构建的冻结事实台账。C 的卡命中只存在于编排器侧 manifest。只有 B 可在 `mode=diagnostic_only`、`purpose=evaluation/diagnostic`、`acceptanceEligible=false` 时携带严格 `indexHints` 并保持 `proseEvidence=[]`;`claimLedger` 不得引用 `indexHints`。该例外不能用于 A/C 或产品生产。
### 7.2 `WriterOutput v1`
```text
schemaVersion
runId / attempt / mode / qualityPolicyVersion
contextSnapshotId / contextSnapshotSha256
candidateVersion
candidateSha256
acceptanceEligible
candidateBody
claimLedger[]
evidenceRequests[]
newSettingDeclarations[]
selfCheck
```
`diagnostic_only` 输出必须固定 `acceptanceEligible=false`;confirm 对此状态硬拒绝。
`candidateBody` 在计算 hash 和 offset 前统一为 UTF-8、Unicode NFC、LF 换行。`candidateSha256` 对该规范化字节计算。`claimLedger[]` 至少包含:`claimId`、`candidateSha256`、`startCodePoint`、`endCodePoint`、事实类型、`factEvidenceId`、可选 `proseEvidenceId`、coverageState;范围采用 Unicode code point 的左闭右开区间 `[start,end)`。规则门机械校验范围、hash 和引用完整性;detector 判断语义是否真的匹配。
## 8. 篇幅与叙事基线
### 8.1 确定性算法
1. 正文先统一为 Unicode NFC 和 LF;“汉字数”= Unicode Script=Han 的 code point 数,不计标点、空白、拉丁字母和数字。
2. “有效章节”= Canonical、汉字数 >= 500、非空章、章号 `< targetChapter`。
3. 有细纲显式 `targetChars` 时使用该值,但仍执行 2000-10000 限幅;该字段需加入 outline schema。
4. 否则取最近 `min(20, 有效章节数)` 章的汉字数中位数;偶数样本取中间两值算术平均,使用十进制 `ROUND_HALF_UP` 取整数;不足 3 章时使用作品初始化默认值。
5. `density = hardEventCount + 0.5 * foreshadowingActionCount + 0.5 * requiredSceneCount`。
6. 调整系数 `factor = clamp(0.85 + 0.05 * (density - 3), 0.85, 1.15)`。
7. `target = round_to_100(medianChars * factor)`;`round_to_100` 使用十进制 `ROUND_HALF_UP`;范围端点同样半入取整,最后限制在 2000-10000 字。
回放评测只使用目标章之前的数据,不读取目标章字数。叙事基线同时记录连续四章的场景数、对话占比、段落长度和钩子类型。
## 9. 生产质量状态机
`qualityPolicyVersion = writer-production-v1`
```text
validating_context -> retrieving -> writing -> detecting
detecting -> shadow_ready
detecting -> rewriting(attempt <= 2) -> detecting
detecting -> blocked_user_action(attempt > 2)
shadow_ready -> accept_preflight / edited_candidate / discarded
edited_candidate -> detecting
accept_preflight -> accepted / revision_conflict / authorization_stale / source_stale / quality_stale
accepted -> canonical_committed -> extraction_queued
```
detector 只阻断可定位、可验证的问题:细纲硬约束漏项、事实冲突、证据引用缺失、时间地点/知情范围/能力代价矛盾、未来泄漏、输出合同错误。文风、张力和文笔只给建议或交 judge,不作为 detector 硬阻断。
每个节点都有 deadline;超时标记当前 attempt,取消下游并丢弃迟到结果。产品化状态仍须 compare-and-set、终态不可回退和重试幂等,但不得直接复用第 11 节 agent-example 离线文件状态;具体持久化必须在 Gate B 通过后按父仓运行时边界设计或另立 ADR。
`accept_preflight` 必须实时校验:`mode=production`、`acceptanceEligible=true`、qualityPolicyVersion、detector 报告绑定的 candidateSha256/candidateVersion、授权快照仍有效、sourceStatus 未变化、contextSnapshot 未失效、`expectedRevision` 一致。用户修改后合并必须生成新 candidateVersion、重新跑 detector,再回到 Shadow 展示与接受前置校验。
生产自动返修最多 2 轮。用户可在阻塞后手动发起新运行,不复用旧 candidateVersion。
## 10. 离线优化与双盲评测
`qualityPolicyVersion = writer-eval-v1`
- 状态机:`preregistered -> generating -> detecting -> judging_pair -> stable_report`;双评不稳定时进入 `adjudicating -> adjudicated_report`;第三评委报告非法进入 `failed_judge_invalid`,第三评委后仍无稳定配对进入 `failed_judge_unstable`;授权、冻结、合同或模型失败进入对应 `failed_*` 终态。
- 离线优化允许最多 5 轮,且每轮只改一个变量;与生产两轮返修是两套状态机。
- 三臂使用相同细纲、冻结点、完整模型 ID、effort、单次预算、上下文上限、篇幅算法和输出 schema;A/C 还必须使用相同原文字符预算和统一事实约束。启动前对完整 WriterContext 执行 allowlist diff,只允许原文内容/来源及派生 hash 不同;出现其他差异即失败。
- A/B/C 运行顺序由整个预注册评测集一次性生成:先按 `SHA-256(evaluationSetVersion + sampleId)` 排序全部样本,再按索引循环分配 `[A,B,C]`、`[B,C,A]`、`[C,A,B]`。生成完整顺序表后机械验证每个位置上的臂计数差不超过 1;禁止逐样本独立 shuffle。盲化映射使用同样的评测集级分配原则和独立命名空间。
- judge 的可信输入边界是独立 `writer-blind-input-v2`:盲化候选/哈希、所有臂相同的细纲评测字段,以及 evaluator-only `oracleTruthPack`。真实 A/B/C 映射仅在编排器内存中存在,judge 不得访问各臂 WriterContext、原始运行目录或含臂名的路径。
- 两个评委使用独立无会话实例,第二评委反转顺序;评分步长为 0.5。
- 同维分差 > 0.5 时判不稳定,最多增加一次第三评委。三评分中若至少一对差值 <=0.5,则该维最终分取三者中位数;若不存在稳定配对,则样本进入 `failed_judge_unstable`,顶层运行失败。
- 五维:设定与实体保真、情节与细纲忠实、叙事完整与张力、文风一致、文笔质量。
- 离线达标不改变 detector 红线。评委可以看到独立真值包,但不能看到被测卡、各臂检索轨迹或臂专属补充原文。
`oracleTruthPack` 固定为 `oracle-truth-pack-v1`,由可信 loader 在同一冻结快照内生成:全量 Canonical 历史中 `chapter <= asOf` 的事实断言,加上目标章 reference scaffold 中预注册的目标事实断言。它至少包含 `schemaVersion/evaluationSetVersion/sampleId/workId/asOf/sourceSnapshotSha256/authorizationSnapshotId/historicalAssertions[]/targetAssertions[]/packSha256`;每条断言带稳定 ID、来源版本、章号边界和内容 hash。包中不得包含被测卡、卡派生断言、A/B/C 检索 manifest、各臂原文或目标章文风答案。
`oracleTruthPack` 的授权快照必须固定 `allowedPurpose=offline_evaluation`、来源状态、来源版本和重验时间,只授权本次 evaluator;所有 judge 接收字节完全相同的 pack。它不进入 writer、detector、Gate 安全摘要或日志;原始包只在 raw vault 临时存在,长期只保留 schema/hash/授权回执。其历史断言用于核对远端历史事实,目标断言用于核对细纲和目标事实,不得用任一臂检索到的补充原文给候选背书。授权失效、schema/hash 不一致或三位评委 pack hash 不同,样本失败。
### 10.1 两级验收门
| 门 | 有效样本 | 机械通过条件 | 其他终态 |
|---|---|---|---|
| Gate A 链路可运行 | 深空预注册 5 章,五类场景各 1 | 5/5 schema 合法且评委稳定;未来泄漏 0;系统失败 0;C 臂 detector 最终高严重度 0;细纲硬约束覆盖率 100% | 任一系统/schema/hash/泄漏/judge 异常=`failed`;仅预注册集合自身不足 5 或场景不全=`insufficient_evidence` |
| Gate B 正文层正式通过 | 至少 2 本书、每书 >=5 章、总计 >=10 章;五类场景均覆盖 | Gate A 已 passed;A/C 所有样本合法且稳定;C-A 的“设定与实体保真”平均增量 >=0.25 且至少 60% 样本增量 >0;“文风一致/叙事张力”整体及各非空新角色分层均不退化;C 臂硬约束覆盖率 100%、高严重度 0 | 任一系统/schema/hash/泄漏/judge 异常=`failed`;仅预注册作品/样本/场景自身不足=`insufficient_evidence`;无明显增益且无退化=`no_gain`;B 不参与通过阈值 |
裁决按以下顺序执行,命中即停止,保证每次只有一个终态:
1. **Gate A**:先检查预注册 manifest、顺序表、allowlist diff、全部预期调用回执、schema/hash、泄漏审计和 judge 稳定性,任一异常 -> `failed`;再检查预注册集合定义时是否已经不足 5 个样本或五类场景不全,命中 -> `insufficient_evidence`;再检查 C 臂硬门,命中 -> `failed`;其余 -> `passed`。
2. **Gate B**:先检查本次 Gate B 的全部系统/schema/hash/泄漏/judge 状态,任一异常 -> `failed`;再继承 Gate A 终态,Gate A=`failed` -> `failed`,Gate A=`insufficient_evidence` -> `insufficient_evidence`;再检查预注册作品/样本/场景自身规模,不足 -> `insufficient_evidence`;再检查 A/C 硬错误、整体或任一非空新角色分层质量退化,命中 -> `failed`;再判断 C-A 保真增益,达标 -> `passed`;其余 -> `no_gain`。B 只进入诊断报告,不进入这些阈值。
只有 Gate B=`passed` 才解锁细纲智能体真实能力验收;`no_gain` 只形成“卡未证明增益”结论,不视为通过。
### 10.2 Task10 Gate A 预注册与当前可验证边界
唯一配置为 `.claude/skills/replay-eval/configs/writer-gate-a-deep-space-v1.json`。样本固定如下,不得根据生成结果替换章节或场景分类:
| 目标章 | 冻结点 | 场景 | 预注册目标 | 大纲/细纲来源 | 预期长度 | 主要实体 | 新角色比例 | 泄漏检查 |
|---:|---:|---|---|---|---:|---|---:|---|
| 489 | 488 | 战斗 | 圣蒂曼围攻/加特朗战 | `outline-window:deep-space:481-488` / `fine-outline:deep-space:489` | 7500 | 圣蒂曼、加特朗 | 1.0 | 禁读 489 及以后;目标/未来读取数必须为 0 |
| 321 | 320 | 人物对话 | 莫妮卡道别与朋友确认 | `outline-window:deep-space:313-320` / `fine-outline:deep-space:321` | 7600 | 莫妮卡、朋友关系 | 0 | 禁读 321 及以后;目标/未来读取数必须为 0 |
| 544 | 543 | 转折 | 迷途之地内应反水 | `outline-window:deep-space:536-543` / `fine-outline:deep-space:544` | 6700 | 迷途之地、内应 | 未知 | 禁读 544 及以后;目标/未来读取数必须为 0 |
| 199 | 198 | 信息揭示 | 赛莉丝身份与联赛锁死真相 | `outline-window:deep-space:191-198` / `fine-outline:deep-space:199` | 2000 | 赛莉丝、联赛 | 0 | 禁读 199 及以后;目标/未来读取数必须为 0 |
| 523 | 522 | 老角色回归 | 伊蕾莉雅与旧部重逢 | `outline-window:deep-space:515-522` / `fine-outline:deep-space:523` | 6100 | 伊蕾莉雅、旧部 | 0 | 禁读 523 及以后;目标/未来读取数必须为 0 |
预期长度不是人工填写:配置记录目标章之前连续四章的 `frozenRecentHanCounts`,统一以 `hardEventCount=1`、`foreshadowingActionCount=0`、`requiredSceneCount=0` 调用 `calculate_target_chars`,且 `usesTargetChapterLength=false`。五章机械结果固定为 489=7500、321=7600、544=6700、199=2000、523=6100;上下限取正负 10% 后再受 2000-10000 限幅。
新角色比例只统计具名 `requiredCharacters` 在冻结点前无记录的比例。真实 loader 在来源、授权、scaffold、卡和正文所在的同一个 `REPEATABLE READ READ ONLY` 事务内,直接扫描冻结历史 Canonical 正文并返回名字对应的首次命中章与命中章集合,再独立重算 `knownBeforeAsOf/absentBeforeAsOf/newCharacterRatio`,不得相信卡内是否出现该名字。489 的加特朗在 488 前无记录,因此为 1.0;321/199/523 的具名角色已有记录,因此为 0;544 的“内应”是泛称、无法机械判定具体身份,必须为 `null + unresolved_generic_role`,不允许默认成 0。
真实装配把目标章 reference scaffold 分成两份:writer 只接收预注册细纲硬约束和统一事实约束;scaffold 的目标事实断言只进入 evaluator-only oracleTruthPack。完整 scaffold、目标断言和原文答案均不得进入 writer。这项验证不覆盖上游清洗、抽卡、范式、细纲生成或完整创作链,不能据此宣称整条创作链完成。
仓内配置不含原文全文。`writerContextInput.contentMode=sanitized_contract_fixture`,连续四章只放脱敏合成短文本,用于 dry-run 机械证明 WriterContext 合同、冻结边界、三臂差异、manifest 可复现和候选不可接受;不能据此声称历史原文完整、生成质量通过或 real-run 完成。
dry-run 命令:
```bash
.venv/bin/python .claude/skills/replay-eval/scripts/run_writer_replay.py \
--config .claude/skills/replay-eval/configs/writer-gate-a-deep-space-v1.json \
--dry-run
```
dry-run 只生成计划、manifest 和上下文摘要,不调用模型。测试注入路径虽可验证 writer、detector 与盲评编排,但 judge 只接收独立盲化内容和共同评测参考,不能取得 raw 目录、真实臂映射或任一臂专属证据;评委顺序变化不得改变共同参考。当前真实 semantic detector 与 judge adapter 尚未实现,CLI `--execute` 必须明确失败关闭;在 adapter 接线、离线测试和预算确认完成前,不得声称真实回放或 Gate A 已完成。
当前实现与本版合同仍有明确差距:writer runner 只把 `opus` 当模型参数,未绑定绝对 CLI/hash、完整 model ID、单次预算与输出 schema,也未形成联合回执,stderr 仍可能泄漏;配置仍使用旧三臂证据策略、`inputProvenance=oracle_reference_scaffold` 和 temperature/topP/seed 数值;顺序仍是逐样本处理,缺少全评测集平衡表与完整上下文 allowlist diff;真实 oracleTruthPack、semantic detector、blind judge、GateInputBuilder、confounders、vault lease 和文件 CAS 未接线;测试注入仍把 detector 指标写死,`writer_gate.py` 及错误测试仍可能先判样本不足。以上任一项未整改,Gate A real-run 不得启动。
真实 CLI 极小探测还有一条直接证据:一次 Opus 调用等待 177043ms 后因 API 503 失败,进程 `exit=1`;JSON envelope 却同时出现 `type=result`、`subtype=success`、`is_error=true`、`api_error_status=503`、`terminal_reason=api_error`、`stop_reason=stop_sequence`、`total_cost_usd=0`、完整零值 `usage` 和空 `modelUsage={}`。因此 `subtype=success`、合法 JSON、完整 usage 或 `stop_reason=stop_sequence` 都不能单独证明调用成功;该证据也说明每次调用必须有编排器硬 deadline。安全摘要只记录状态码和受控字段,不记录具体网关错误正文。
该失败探测没有产生可验证的成功 `structured_output` 或完整 model ID,只能证明失败 envelope 语义。必须先完成第 11.4 节成功探测,才能冻结离线评测 adapter 所需字段;在此之前 `--execute` 继续失败关闭。
当前 `writer_gate.py` 把样本不足检查放在部分系统失败之前,错误测试也固化了这一顺序;两者必须按 10.1 重写。detector 指标必须来自严格校验的真实语义报告,禁止常量、默认通过或测试替身进入 real-run。第三评委报告非法或仍不稳定时,样本和顶层都必须失败。
### 10.3 Gate 输入与混淆项合同
`GateInputBuilder` 是 manifest/receipts 到 `gate-input.json` 的唯一可信入口,owner 固定为 `.claude/skills/replay-eval` 的可信编排器,由 `run_writer_replay.py` 在所有样本终态后调用。它只读取预注册 manifest、全评测集顺序表、A/C allowlist diff 回执、retrieval manifest、writer/detector/judge 执行回执与报告、oracleTruthPack 回执、泄漏审计和授权回执;逐项校验 schema、hash、run/sample/candidate 绑定后生成严格 `writer-gate-input-v2`。`writer_gate.py` 只接受该文件及其 SHA-256,不得接收手工对象、上游聚合数字或缺失回执的补写数据。
`writer_gate.py` 是 `writerGateBPassedReceipt` 的唯一签发者。它先从 `gate-input.json` 生成严格 `gate-report.json`;只有 Gate B 报告 `status=passed`,才可签发 receipt。receipt 必须包含 `runId/evaluationSetVersion/gateInputSha256/gateReportSha256/gatePolicyVersion/status=passed/issuedAt/receiptRevision/previousStateSha256/receiptSha256`,其中 `receiptSha256` 对除自身外字段的规范 JSON 计算。`failed`、`insufficient_evidence`、`no_gain` 或报告非法时一律不签发。
签发必须进入第 11.5 节同一文件 CAS journal 序列:在 `state.lock` 内先原子落盘并提交 `gate-report.json` 对应 revision,再基于该 `gateReportSha256` 和前一状态 hash 生成 receipt、原子落盘并提交下一 revision;禁止先签 receipt、跨运行复用或在 journal 外补发。细纲 real-run 入口守卫只读取已签发文件,验证 receipt 严格 schema、规范 hash、gate report、gate input、`receiptRevision/previousStateSha256` 与 journal 链全部一致;禁止调用方自算 JSON 冒充 receipt。细纲 dry-run 不要求该 receipt。
`gate-input.json` 不含正文、prompt、完整模型响应、oracle 断言或 raw path。每个样本的 `confounders` 必须完整包含以下字段,缺失、`null` 或默认空对象均使 Gate 输入 schema 失败:
| 字段 | 确定性算法 |
|---|---|
| `falseNegative.A/C` | 对同一 `assertionId` 或 `constraintId`,detector verdict=`pass`、稳定 judge verdict=`fail` |
| `falsePositive.A/C` | 对同一 `assertionId` 或 `constraintId`,detector verdict=`fail`、稳定 judge verdict=`pass`,且 leakage=false |
| `leakage.A/C` | 对应臂 `leakageAuditReceipt.findingCount > 0` |
| `reviewerInstability` | 双评任一维差值 >0.5;第三评委可把样本裁成稳定,但该字段仍为 true;第三评委后不稳定则系统失败 |
| `newCharactersWithoutCards` | 冻结点前无记录的具名 requiredCharacters 中,在 C 臂卡检索 manifest 无合法卡命中的数量、分母、ratio 与名称集合 hash |
Gate B 必须按预注册 `newCharacterRatio` 分为 `zero=0`、`low=(0,0.5]`、`high=(0.5,1]`、`unresolved` 四层,逐层报告样本数、C-A 五维增量、正增益比例、detector 假阴/假阳和无卡新角色。整体平均仍可用于增益阈值,但任一非空层出现硬错误或超过 10.1 的文风/张力退化线,Gate B 必须失败,不能用单层整体平均掩盖。
混淆项只按同类、同 ID verdict 计算:事实断言只能比较 detector `assertionVerdicts[]` 与 judge `oracleAssertionVerdicts[]` 的同一 `assertionId`,硬约束只能比较双方 `hardConstraintVerdicts[]` 的同一 `constraintId`,不得跨类型配对。预注册 manifest 固定 `comparableAssertionIds`,它必须等于 detector 冻结事实清单的完整 ID 集,并且是 oracleTruthPack assertion ID 集的子集;硬约束预期集来自预注册细纲。detector 与稳定 judge 必须完整覆盖各自预期集,每个 ID 仅出现一次。任一 verdict=`unknown`,或 ID 缺失、重复、越界、candidateSha256 不同,均使 confounder 计算失败并将样本置为 `failed`。五维分数不得推导或覆盖 verdict。
## 11. agent-example 离线评测 adapter 执行合同
本节是 agent-example 内 writer、semantic detector、blind judge 的离线 real-run 合同。它是为固定模型、独立预算和可审计回放设立的有限例外,不是 Muse 产品运行时方案。第 10.2 节只描述 Gate A 样本和当前实现状态,不再另定义调用参数、隔离或失败语义。
### 11.1 可信编排器与统一调用基线
可信编排器是唯一可以读取授权来源、装配输入、持有 A/B/C 映射、管理预算、写临时数据和推进状态的进程。三个模型角色都直连固定 Claude CLI,不调用 `chat_governed`,也不写 New-API 共享额度账本;但每次外发仍必须绑定授权快照、单次/总预算和执行回执。该例外在 Gate B 通过前不得接入产品路径。
Gate B 通过后的产品化必须回到父仓 `AI Orchestration -> Integration Execution Facade -> New-API` 边界;若该边界不能满足需求,必须另立正式 ADR 并评审通过,不能把本节直连 CLI 当成生产方案。
每次模型调用必须是 fresh process,并显式绑定以下已验证参数:`--print`、`--bare`、`--model`、`--effort`、`--max-budget-usd`、`--output-format json`、`--json-schema`、`--tools ""`、`--no-session-persistence`、`--disable-slash-commands`、`--strict-mcp-config`、`--mcp-config '{"mcpServers":{}}'`、`--system-prompt`。`--print` 是非交互执行及预算、JSON 输出、无会话参数生效的前提;`--bare` 用于跳过 hooks、LSP、插件同步、归因和 auto-memory。业务输入只从 stdin 传入,不得把正文、完整 prompt 或臂名写进命令行参数。
| `ExecutionProfile` 字段 | 约束 |
|---|---|
| `profileVersion/adapterRole` | 固定合同版本;角色为 `writer`、`semantic_detector`、`blind_judge` |
| `claudeExecutablePath/claudeExecutableSha256/claudeCliVersion` | 绑定绝对路径、可执行文件 SHA-256 和版本 `2.1.211`;任一变化先重新预注册 |
| `modelAlias/resolvedModelId/effort` | `opus` 只可作配置输入别名;预检探测解析完整 model ID,实际调用和回执都使用该完整 ID,禁止降级换模 |
| `maxBudgetUsdPerCall/timeoutSeconds` | 每个角色分别预注册;到限即失败,不扩大、不借用共享账本 |
| `maxContextChars` | 在装配前校验;A/B/C writer 上限完全相同;A/C 超限不得截断硬约束或连续四章基线,B 臂沿用第 7.1 节诊断例外 |
| `jsonSchemaId/jsonSchemaSha256` | 输入输出都绑定严格 schema;额外字段、缺字段或 hash 不一致均失败 |
| `systemPromptId/systemPromptSha256` | 三臂 writer 完全相同;所有评委也完全相同,评委编号只进执行元数据,不改变提示词 |
| `temperature/topP/seed` | 固定记为 `unsupported`,`reproducibilityClaim=not_claimed`;不作为 CLI 参数或已绑定控制项 |
三臂 writer 的 `resolvedModelId/effort/maxBudgetUsdPerCall/maxContextChars/jsonSchemaSha256/systemPromptSha256` 必须逐字段相等,并对规范化配置计算同一 `executionProfileSha256`。回执缺完整 model ID 或与预注册值不一致即失败。detector 对所有候选使用同一 detector profile;所有 judge 调用使用同一 judge profile。
每次调用都由 `sandbox-exec` profile 拒绝隔离目录之外的文件读写,只允许 Claude CLI 完成模型调用所需的 DNS、代理和出站网络;工具、插件、hooks、技能、MCP 和其他网络用途全部禁止。cwd、HOME、TMPDIR 均指向本次 0700 隔离目录,调用结束即清理。可执行文件使用已绑定绝对路径,因此不传继承 PATH。
环境只允许以下字段:认证 `ANTHROPIC_API_KEY` 或 `CLAUDE_CODE_OAUTH_TOKEN` 中经授权的一种;代理 `HTTPS_PROXY/HTTP_PROXY/NO_PROXY` 及对应小写字段;locale `LANG/LC_ALL`;证书 `SSL_CERT_FILE/SSL_CERT_DIR/NODE_EXTRA_CA_CERTS`。HOME/TMPDIR 由编排器覆盖,其他 repo、数据库、云平台和业务 secret 一律不继承。blind judge 每次调用都使用新目录、新进程和新 stdin,不得发现 raw 目录、真实 A/B/C 映射或含臂名路径。
### 11.2 三类输入输出
| 角色 | 唯一输入 | 唯一业务输出 | 失败关闭条件 |
|---|---|---|---|
| writer | 严格校验的 `WriterContext v1`;A/C 只含统一事实约束与选出的历史原文,不含卡语义、检索策略或完整 manifest;B 为独立诊断例外 | `WriterOutput v1`;候选正文、claim ledger、补证请求、新设定申报、自检 | 上下文/输出 schema 非法,A/C allowlist diff 失败,预算或超时,完整 model ID 不符,候选与上下文 hash/版本不绑定 |
| semantic detector | `semantic-detector-input-v2`;候选、细纲硬约束、claim ledger、允许核对的冻结前证据和上下文绑定 | `semantic-detector-report-v2`;findings、`assertionVerdicts[]`、`hardConstraintVerdicts[]`、证据定位及报告 hash | 报告非法、候选绑定不符、verdict 为 unknown、ID 集不完整、结论无受控证据或高严重度残留 |
| blind judge | `writer-blind-input-v2`;盲化候选、统一细纲评测字段和字节相同的 oracleTruthPack | `blind-judge-report-v2`;五维评分、`oracleAssertionVerdicts[]`、`hardConstraintVerdicts[]`、候选/pack hash | pack 授权/hash 不同、verdict 为 unknown、ID 集不完整、看到臂专属证据、schema/候选/顺序非法,或第三评委后仍不稳定 |
`semantic-detector-input-v2` 必须包含 `schemaVersion/runId/sampleId/opaqueArmId/candidateSha256/candidateBody/contextSnapshotSha256/fineOutline/hardConstraints/claimLedger/factEvidence/proseEvidence/asOf/authorizationSnapshotId/inputSha256`;不得包含 oracleTruthPack、目标章或未来章正文。`semantic-detector-report-v2` 必须包含 `schemaVersion/runId/sampleId/opaqueArmId/inputSha256/candidateSha256/modelReceiptSha256/findings[]/assertionVerdicts[]/hardConstraintVerdicts[]/status/reportSha256`。两类 verdict 数组分别绑定稳定 `assertionId` 或 `constraintId`、`candidateSha256`、`verdict=pass|fail|unknown` 和受控证据引用。编排器只从 schema、hash、候选和 ID 集均合法的报告计算 `highSeverityCount` 与 `hardConstraintCoverage`;unknown 或 ID 集不完整时报告非法,禁止填默认值。
未来泄漏不交给 semantic detector 猜测。可信编排器单独执行 `leakage-audit-v1`:只在编排器边界内比较候选与预注册 `forbiddenFacts[]`、目标/未来读取 trace、`asOf` 和来源 hash,输出不含禁区正文的 `leakageAuditReceipt`。禁区事实不得进入 writer、judge、日志或安全摘要;Gate 只消费该回执的 `status/findingCount/receiptSha256`。
`blind-judge-report-v2` 必须包含 `schemaVersion/runId/sampleId/reviewerInvocationId/blindInputSha256/oracleTruthPackSha256/candidateOrder[]/candidateScores[]/oracleAssertionVerdicts[]/hardConstraintVerdicts[]/modelReceiptSha256/status/reportSha256`。每个 `candidateScores[]` 项绑定 `blindCandidateId/candidateSha256`,并为五个维度逐项给出 0.5 步长分数和受控理由。两个 verdict 数组中的每一项分别绑定稳定 `assertionId` 或 `constraintId`、`candidateSha256`、`verdict=pass|fail|unknown` 和受控证据引用;证据只能引用候选区间、oracle assertion 或预注册 constraint,不得引用臂专属检索材料。`candidateOrder[]` 必须与本次 stdin 完全一致;分数与 verdict 独立,禁止用分数阈值生成 verdict。
每份 judge 报告先独立校验,再进入稳定性裁决。第三评委不是容错兜底:其报告 invalid,或三份报告仍找不到稳定配对,样本分别进入 `failed_judge_invalid` 或 `failed_judge_unstable`,顶层运行失败。失败样本不得进入 Gate A 的有效样本分母,也不得以“有效样本不足”掩盖系统失败。
### 11.3 敏感临时数据
原文、候选正文、完整模型输入和完整模型响应只允许写入 `/private/tmp` 下本次运行的独立 raw vault。批准角色只能是用户/创始人;写入任何 raw 字节前,先在非敏感文件 journal 原子持久化 `vaultLease`,绑定 `authorizationId/approvedBy/runId/vaultId/sourceVersion/contentHashes/createdAt/retainUntil/purpose`。没有有效 lease 不得创建 vault。
vault 路径由可信编排器生成不可猜测 ID,拒绝调用方传入绝对路径、`..`、软链接和任何 realpath 逃逸。目录权限固定 0700,文件固定 0600;创建、打开、重命名和清理全程拒绝 symlink 跟随。恢复时先扫描所有未关闭 lease:对应 vault 存在则进入清理流程,不存在则补记关闭回执,禁止留下无 lease 的孤儿 raw 目录。
默认在安全摘要和最终状态原子落盘后立即清理 raw vault。只有单独的调试授权记录 `authorizationId/approvedBy/runId/vaultId/sourceVersion/contentHashes/retainUntil/reason` 才可保留,授权不得跨运行复用,最长 24 小时。清理成功前运行不得进入 `completed`;失败进入 `failed_raw_cleanup`,由可信清理器持久重试并保持 vault 隔离,24 小时仍未清除升级为安全事件。任何状态都继续禁止输出 raw path。
日志、安全摘要和长期报告不得包含原文、候选正文、完整 prompt/response、raw path、真实臂映射或可反推内容的片段。stderr 不落盘、不回显原文;adapter 只输出稳定失败码、退出码、长度/hash 和预定义受控摘要。
### 11.4 运行回执、预算与失败语义
每次调用都产生不含正文的 `ExecutionReceipt`,至少记录 `adapterRole/invocationId/requestedModelId/actualModelId/modelMatch/effort/maxBudgetUsdPerCall/totalCostUsd/usage/modelUsage/stopReason/terminalReason/isError/apiErrorStatus/exitCode/durationMs/inputSha256/structuredOutputSha256/jsonSchemaSha256`。CLI 结果未提供完整实际 model ID、`total_cost_usd`、usage、modelUsage、stop reason 或 terminal reason,或任一字段无法归一化时,回执非法,不能把该调用算作成功。
`envelope.structured_output` 是唯一业务对象,必须直接通过该角色的严格 JSON schema;`envelope.result` 只作审计和受控错误分类,禁止解析为业务 JSON,也禁止作为 structured_output 缺失时的 fallback。当前 503 探测没有证明 2.1.211 成功响应的 `structured_output` 字段形状;实现前必须完成一次极小成功探测并冻结 envelope schema/hash。该探测未成功前 Gate A 不得启动。
调用成功必须联合满足:进程 `exitCode=0`;envelope `type=result` 且 `is_error=false`;`terminal_reason` 属于该角色预注册的正常终止集合;业务输出通过严格 schema;`modelUsage` 能证明实际模型且与请求模型一致;`usage` 结构和数值合法并可核账。`subtype=success` 与 `stop_reason` 只作审计字段,不能覆盖非零退出、`is_error=true`、API error、空 `modelUsage` 或 schema 失败。
每个 real-run Gate 启动前都必须单独确认 `totalBudgetUsd`,并在预注册配置中列出 writer、detector、judge 的单次预算、最大调用次数和最坏总额。实际美元成本以 envelope `total_cost_usd` 为权威值,按 JSON 十进制原值解析并统一到 6 位小数、`ROUND_HALF_UP`;若 `modelUsage` 提供分模型 `costUSD`,其同规则求和后必须与权威值一致,否则回执非法。编排器在每次启动前预留最坏预算,累计 `totalCostUsd` 与预留上限都不得超过该 Gate 总预算;缺字段、超总额或 CLI 因预算停止都失败关闭。
| 稳定失败码 | 触发条件 |
|---|---|
| `{ROLE}_TIMEOUT` | 超过该角色 deadline;取消下游并丢弃迟到输出 |
| `{ROLE}_NONZERO_EXIT` | Claude CLI 非零退出;stderr 仅转为受控摘要 |
| `{ROLE}_API_ERROR` | `is_error=true`、`terminal_reason=api_error` 或存在 API 错误状态;不记录网关错误正文 |
| `{ROLE}_RECEIPT_INVALID` | envelope 或联合回执缺字段、terminal reason 非法、成本无法对账 |
| `{ROLE}_SCHEMA_INVALID` | CLI 包装、业务输出或报告不符合严格 schema |
| `{ROLE}_BUDGET_EXCEEDED` | 单次预算停止、累计预算超限或 usage 无法核账 |
| `{ROLE}_MODEL_MISMATCH` | 实际 model 缺失或与预注册 model 不一致 |
| `JUDGE_INVALID` | 任一必需 judge 报告非法;第三评委非法时样本直接失败 |
| `JUDGE_UNSTABLE` | 第三评委后仍无稳定配对 |
一个异常只产生一个 `primaryCode`,其余命中项进入不含敏感信息的 `causes[]`。主码优先级固定为:`TIMEOUT > API_ERROR > NONZERO_EXIT > RECEIPT_INVALID > BUDGET_EXCEEDED > MODEL_MISMATCH > SCHEMA_INVALID > JUDGE_INVALID > JUDGE_UNSTABLE`。实测 503 因此归 `API_ERROR`,非零退出、空 modelUsage 和零值 usage 只作 causes。任一失败码都使当前样本 `ok=false`、`acceptanceEligible=false`,并停止该样本后续调用;不得换模型、扩大预算、跳过失败臂或把系统失败降级成普通质量分。
### 11.5 文件型 CAS 与原子写
离线评测 adapter 不使用内存状态作为真实执行依据。每个运行维护不可变 `states/<revision>.json` journal,`state.json` 固定为当前 revision 的完整内容副本,不是路径指针。revision 至少包含 `runId/sampleId/arm/attempt/candidateVersion/state/revision/previousStateSha256/resultSha256/safeSummarySha256/cleanupState`。
状态目录通过已验证父目录 fd 使用 `openat` 与 no-follow 语义访问,拒绝路径替换和 symlink;固定锁文件 `state.lock` 在状态目录内排他创建,并用 `fcntl.flock` 包围读、比较、写全过程。推进时先排他创建 0600 revision 临时文件并 `fsync`,rename 为不可变 revision;再写 0600 `state.json.tmp`、`fsync`、rename 覆盖 `state.json`,最后 `fsync` 状态目录。结果、安全摘要和清理标记先原子落盘,其 hash 随同一 revision 提交,未被 revision 引用的文件不算已提交。
旧 revision、旧 attempt、旧 candidateVersion、重复终态和迟到结果统一返回 `CAS_CONFLICT`,不能覆盖较新状态。非敏感 journal 保留到运行审计期结束,使 `previousStateSha256` 可逐版验证。进程崩溃后比较 `state.json` 与不可变 journal,恢复最后一个 schema 合法、hash 链与关联文件 hash 完整的 revision;临时文件、孤儿文件、断链状态、异常锁或未关闭 vault lease 一律先失败关闭并清理,不得继续模型调用。
### 11.6 Gate A 绑定
Gate A real-run 只允许使用满足本节合同的离线评测 adapter。执行前必须机械证明:成功 structured_output 探测已冻结;Gate A 总预算与单次预算已确认;A/C 执行配置、事实约束和原文字符预算相等;全评测集顺序表平衡;完整上下文 allowlist diff 通过;temperature/topP/seed 为 `unsupported/not_claimed`;三类 schema、oracleTruthPack、GateInputBuilder、泄漏审计与回执测试通过;judge 隔离无法发现 raw、映射和臂名;raw lease、vault 权限/逃逸/保留/清理测试通过;文件 CAS journal 的并发、崩溃和迟到结果测试通过。Gate B 启动前另行预注册并批准独立预算,不得沿用 Gate A 批准。
本次设计修订只定义合同,不等于 adapter 已实现,更不等于 Gate A 已运行或通过。真实 `--execute` 在第 10.2 节列出的缺口全部关闭、机械测试通过且预算获批前,必须继续失败关闭。
## 12. 用户闭环与下游交接(Gate B 后第二阶段)
本节不在 Gate A/B 前实现。Gate B=`passed` 后,Shadow 候选展示才提供三决策:
1. 原样接受;
2. 修改后合并,带 `expectedRevision`;
3. 丢弃。
原样接受和修改后合并都必须经过 `accept_preflight`。修改后合并先生成新 candidateVersion 并重新 detector;原样接受也必须重新校验授权、来源、质量策略、candidate hash 和 `expectedRevision`。通过后才调用 confirm;版本冲突返回 `revision_conflict`,不得静默覆盖。Canonical 提交后异步触发章后抽取,产出知识草稿和冲突队列;正文层只定义交接合同,不直接审批知识入库。
## 13. 分阶段实施计划与 SoT 回填
**第一阶段:做到 Gate B 裁决、receipt 签发和细纲入口守卫。**
1. 实现 A/C 两种原文检索、B 负对照、统一事实约束、相同原文字符预算、全评测集顺序表和完整上下文 allowlist diff。
2. 实现 writer 生成、真实 semantic detector、evaluator-only oracleTruthPack、隔离 blind judge、逐断言/逐约束 verdict、泄漏审计、混淆项合同、唯一 GateInputBuilder 与 `writer_gate.py` 新裁决顺序。
3. 实现第 11 节离线 CLI adapter:绝对可执行文件/hash/版本、完整 model ID、sandbox、structured_output、预算/回执、raw lease/vault、文件 CAS 和原子结果。
4. 在第一阶段实现 `writer_gate.py` 唯一 receipt 签发器和细纲 real-run 入口守卫;覆盖系统失败优先、同 ID verdict、unknown/ID 集失败、gate-report 先落盘、非 passed 不签发、journal/hash 链验签和拒绝自算 JSON 的机械测试。
5. 用户批准 Gate A 预算后 real-run;通过后另批 Gate B 独立预算并执行。第一阶段不得实现 Shadow、confirm、Canonical 写入、章后抽取或父仓产品化回填。
**第二阶段:仅在 Gate B=`passed` 后启动。**
6. 使用第一阶段已经实现的入口守卫实际启动细纲 real-run;必须提交由 `writer_gate.py` 签发并通过 journal/hash 链验证的 `writerGateBPassedReceipt`。细纲 dry-run 继续豁免。
7. 接通 Shadow 三决策、confirm、Canonical 和异步抽取;按父仓 AI Orchestration、Integration Execution Facade、New-API 边界完成产品化,或先评审正式 ADR。
8. 回填父仓设计、API 契约、schema 和索引,删除重复定义;任务完成后蒸馏并删除本文。
## 14. 实施前门禁
- 本修订版通过产品流程与技术合同两类独立评审。
- 用户确认本文为正文智能体实验台任务 SoT。
- 第 11 节离线评测 adapter 未实现前,真实 `--execute` 保持失败关闭;设计评审通过不代表实现完成。
- Gate A real-run 前,用户明确批准总预算、三类单次预算、最大调用次数和 raw 最长保留期。
- Gate B real-run 前,按其样本集另行批准独立总预算、三类单次预算、最大调用次数和最坏总额。
- writer、semantic detector、blind judge、oracleTruthPack、GateInputBuilder、Gate B receipt 签发器与细纲入口守卫的严格 schema、隔离、回执、路径安全、文件 CAS 和失败码均有机械测试证据。
- Gate B 未通过,禁止实现或接入 Shadow/confirm/Canonical/章后抽取产品路径,禁止父仓产品化回填。
- `writer_gate.py` 只为 passed Gate B 报告签发不可变 receipt;细纲 real-run 必须通过 journal/hash 链验签,拒绝自算 JSON;dry-run 明确豁免。
- 独立范式抽取继续运行,但不得与正文实现共享改动文件或进程。
- 细纲真实回放保持暂停,直到正文 Gate B 通过。