# 两个仓库的覆盖审计：第 7 节遗漏了什么？

**原四点不足以代表项目全貌；第 2 点需要改写，第 3—4 点需要明确适用范围。** 本次把它扩为 14 项产品接入问题，并复核主要应用、SDK/Tools 和 Worldbook Service 路径。

基线：Harness `80aef3fa5582d8508ecdd1afa206391940ce9502`；Worldbook `3a11e333afd335aeff165e0ccc3654af8e1897d1`。这是代码与已有测试断言的阅读审计，没有运行真实模型、完整测试或生产故障演练。源码事实、产品含义和未核验范围分别标注。

[打开更新后的逐节导读](rp-business-guide.html#section-7)。本报告保留更多实现细节，供技术追证据；不是给当前系统自动新增这些保障。

## 优先看三个修正

- **执行在后台，仍可补本轮消息。** 图片就是现成反例，所以要分别描述是否阻塞正文与结果何时生效。
- **普通 Agentic 后台走状态候选，不代表全项目只有这一条上下文注入通路。** 其他路径有 promptContent、system overlay、模板变量、DIO、世界书等机制；是否启用取决于实际接线。
- **“采用正文”要有业务定义。** Story 当前核对权威存储的正文及消息锚点，不是用户点赞；正文成功、状态保存成功、后台任务完成需要分别观察。

本次还纠正了此前世界书说明中的递归默认值：原生 Entry 默认禁止参与，文件导入器对省略字段默认填 false，允许参与。已同步修改相关导读与条目选择说明。

## 核查到什么程度

| 范围 | 这次覆盖 | 不能据此推定 |
| --- | --- | --- |
| Harness 应用 | 场景/入口，Emochi Actor、前台工具、普通 Agentic、Story、记忆/Compact 边界，Sumi 图片副作用等关键路径 | 每个应用配置、所有编辑分支和所有生产组合已经完整测试 |
| SDK / Tools | Agent/Slow/FastSlow、注册、工具生命周期、状态接口、预算、取消、后台任务、观测与构建身份 | 自动拥有产品权限、幂等、持久化任务和统一业务提交 |
| Worldbook Service | 管理/导入、静态兼容、原文修订、选择、索引、预算与降级、tenant 边界 | 完整 SillyTavern 兼容、所有外部文件保真、生产访问策略已验证 |
| 跨服务 | Harness RPC 消费端与 Worldbook HTTP 服务契约 | Axon、Node API、Kaon 等外部仓库内部实现已经审计 |
| 发布 / 线上 | 源码配置与构建记录机制 | npm 已发布、产品已升级、当前线上配置与流量已确认 |

**因此，本报告可以用于主要业务决策的覆盖检查；不能称作“所有代码逐行审完、100% 无遗漏”。** 各详细项给出的未核验内容应保留在后续技术验收里。

## 额外核到的版本与质量口径

配置文件存在不等于最终采用该配置：Harness 启动时加载选定场景，旧环境变量配置可以整条覆盖同名场景。构建信息可以记录 SDK/Core Tools 版本、源码 SHA、有效配置哈希，但不会冻结远端 ModelConfig。见 [场景覆盖实现](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/scenario-files.ts#L21)、[构建身份](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/build-metadata.ts#L11)。

现有通用文本评估器按预定义 required/forbidden 文本匹配评分，不是完整的剧情语义裁判。该 runner 的 passRate 分母只包含已完成且有评分的样本，失败样本另列，因此展示质量时还需同时看完成率和失败数。见 [评分方式](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/evaluations/scorer.ts#L12)、[报告汇总分母](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/evaluations/runner.ts#L20)。


## 应用层：时序、场景、提交与恢复

### 1. 前/后台与生效轮次是两个维度，不能一一对应

- **当前实现**：前台function-loop选图片时立即放占位、安排图片任务；dispatch用background.schedule("imagine")执行。图片工具等待对应assistant message持久化，然后给该message写narrative.sections的pending图片位置并启动实际图片生成。它补的是当前回复，不必等下一轮。DIO则是另一个后台任务，长期指令供后续轮生效。
- **业务影响**：需求应分别定义“文字首字/完成是否等待”“图片是否稍后回填同一条消息”“失败后占位如何展示”。不可承诺所有后台能力只影响下一轮。
- **原第 7 节是否修正**：**需要，直接修改第2条标题和说明。**
- **证据**：[图片后台安排 dispatch:968–986](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L968)；[前台占位与调度 actor/roleplay-runtime:368–377](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/actor/roleplay-runtime.ts#L368)；[同message回写 tools/imagine-skill:330–359](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/tools/imagine-skill.ts#L330)；[等待消息存在:386–407](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/tools/imagine-skill.ts#L386)；[DIO仅后续轮工具描述:109–115](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/actor/roleplay-runtime.ts#L109)。

### 2. 模块组合和上下文组装归属必须作为产品模式显式确定

- **当前实现**：请求的scenario_id查配置，不是LLM自动选择全部模块。预组装入口用chat-service已准备的messages，记忆前后hooks归chat-service；closed-loop由Harness协同Axon组装。当前世界书限制专用Agentic场景，不能同时preActorDirector/Story/Sumi；Story替换普通Agentic后台分支；Sumi独立且禁止多种其他编排/记忆；普通前台loop与普通Agentic可共存；Agentic+Compact必须声明治理模式，enforce还要求Compact。
- **业务影响**：不能承诺把复选框“世界书+Story+图片+全部记忆”全勾就可用。需求需选择当前模式或明确新增组合开发；配置已有并不证明线上启用。
- **原第 7 节是否修正**：第1条准确，但**需另补场景/入口组合边界**。
- **证据**：[路由 dispatch:289–306](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L289)；[两入口及记忆归属:1244–1291](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L1244)；[互斥/治理 server:715–768](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/server.ts#L715)；[普通loop与Agentic接线/Story分支 dispatch:1110–1164](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L1110)。

### 3. “谁拿到哪些事实”必须约定，不能把共享状态理解成共享全部上下文

- **当前实现**：Actor用渲染后axon.history；世界书blocks只装饰这份Actor消息，Planner取原request.messages或enforce Compact的retainedHistory。memory先召回为externalSetvars再经模板，未引用变量不保证进入Actor。后台未直接拿同批memory.items。前台工具控制器可读当轮Actor段落；普通后台Planner只拿开轮快照。两个后台模型投影/Actor投影的窗口和长度也不同。
- **业务影响**：不能承诺“知识专家已审过Actor本轮使用的全部世界书”“所有召回记忆都被采用”“Planner能修复本轮新写出的错误”。若需要统一校对证据包，要新增明确连接和时序。世界书内容只能在Actor实际写出、宿主保存、未来请求带回且落入可见窗口等条件下间接进入Planner。
- **原第 7 节是否修正**：第1条已提到输入但**不足以表达此关键产品限制**；建议加一个明确结论或示例。
- **证据**：[Actor世界书注入 adapter:618–621](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/integrations/roleplay-axon-adapter.ts#L618)；[planningHistory与planningContext runtime:402–478](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L402)；[memory实际rendered追踪 adapter:527–533](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/integrations/roleplay-axon-adapter.ts#L527)；[后台看不到本轮新回复的断言 test:1741–1753](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/agentic-v2.test.ts#L1741)；[真实Actor provider消息:728–737](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/actor/roleplay-runtime.ts#L728)。

### 4. 触发、必选审计、模型升级规则决定成本，也决定是否能承诺“按需”

- **当前实现**：普通Agentic准备成功并进入generate的每个逻辑轮调度一次，Orchestrator先推理后才能选零专家。首轮强制NPC和镜头审计、新名字匹配强制NPC审计（工具启用时）；required审计发生且状态工具启用时，第二阶段还强制Director。Director可能校验不通过、无变化或CAS冲突，所以“强制调用”不等于“必定写状态”。manual仅不自动升级Orchestrator，仍由模型选择tool_calls；auto可按工具数阈值换更强模型重选。
- **业务影响**：若PM要求每X轮、低成本仅事件触发、某类工具绝不执行，需要改策略或allowlist，不能把9条窗口/10–20轮规划跨度当触发间隔。计费估算不能只数Actor一次，也不能把manual当人工审批。
- **原第 7 节是否修正**：**第3条的“可选Director”需补硬规则例外**；整张截图还缺触发与成本边界。
- **证据**：[generate runtime:686–695](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L686)；[once-per-turn:558–575](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L558)；[首轮/姓名规则 agentic-v2:670–702](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L670)；[强制Director:873、912–925](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L873)；[auto升级:803–811、898–910](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L803)；[默认普通续聊仍1次模型测试:192–219](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/agentic-v2.test.ts#L192)。

### 5. Story的“采用正文”与编辑/重生成行为，不等于普通Agentic的状态提交

- **当前实现**：Story当前轮prepare先读上轮pendingActor对应的权威assistant内容、用户锚点与前一accepted消息哈希，匹配才在内存候选上推进。当前Actor成功后，settle保存候选和新的pendingActor，outcome=waiting_for_acceptance；这不是已经按本轮文字完成世界结算。最新pending回复若同ID且相关锚点匹配，采用该ID下实际保存的正文，包括编辑版；关联用户输入或更早accepted正文变化导致锚点失配、pending消息缺失或换ID才重建。regenerate/edit_regenerate由adapter退回原Actor，不做Story模型/状态写；倒退到旧source position也只读降级，初始化明确不可用时也可只生成Actor。
- **业务影响**：“重新生成”“编辑上轮”“继续”不能默认等价于新用户回合。需求需要明确哪些行为推进剧情、哪些只是换一版文字、权威消息由谁保存。不能承诺用户收到Story文字就表示世界已经按该文字持久推进，也不能把接受理解成用户主动点赞。
- **原第 7 节是否修正**：第4条方向正确；**建议明确“业务采用/保存的正文”，并补Story操作语义**。
- **证据**：[权威消息读取 adapter:64–68](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/story/axon-adapter.ts#L64)；[验证锚点 coordinator:190–225](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/story/coordinator.ts#L190)；[prepare内存候选/世界推进:365–387](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/story/coordinator.ts#L365)；[只保存待接受候选:390–425](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/story/coordinator.ts#L390)；[重生成/降级 adapter:34–109](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/story/axon-adapter.ts#L34)；[真实dispatch重生成测试:82–95](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/story-scenario-dispatch.test.ts#L82)。

### 6. 取消、并发与新状态可见性需要单独约定，CAS不是“保证紧接下轮用到”

- **当前实现**：普通Agentic调度未绑定Actor parentSignal；Actor取消后后台仍运行。各轮各自持开轮快照并发；写入带expectedRevision/sourceTurn/sourceMessageId/historyRevision。冲突标记stale_write_rejected，本次不重新读取并重规划。Actor一旦准备完不热更新，新用户很快发下一句也可能再读旧state。
- **业务影响**：不能承诺“停止生成=撤销所有副作用”“最后用户一句一定立即驱动下一句”“旧任务冲突会自动合并重算”。需要明确取消是否撤销、哪些状态可来自取消轮、后台落后如何展示、是否需要等待/串行化/重算策略。
- **原第 7 节是否修正**：第4条取消描述准确；**缺并发可见性与冲突的产品后果**。
- **证据**：[独立后台和快照 runtime:558–605](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L558)；[CAS及终止冲突 agentic-v2:978–993](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L978)；[取消信号不联动测试:1922–1940](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/agentic-v2.test.ts#L1922)；[冲突只提交一次测试:1831–1835](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/agentic-v2.test.ts#L1831)。

### 7. 失败是否挡住用户回复，取决于阶段和模块，不能统一叫“降级”

- **当前实现**：closed-loop场景memoryRecall=fail_turn、memoryIngest=best_effort。世界书有绑定而选择服务不可用会拒绝当轮，并非自动无世界书继续。普通Agentic的后台模型失败返回failed report，通常不影响Actor；但后台所需模板加载在Actor开始之前，准备失败仍可能挡住正文。日记/表格入口被harness await，但Go后端有runner时只等调度，不等全部保存。Story settle内部捕获CAS/其他错误返回report，dispatch没有把该report反写为Actor失败，因此可能正文成功但Story状态保存失败。
- **业务影响**：PM要明确“缺记忆/缺设定时是否允许答”“正文成功但后台失败怎样提示与补救”“状态卡片是否显示保存中/失败”。不能把turn.completed当成所有服务都成功。
- **原第 7 节是否修正**：第4条可保留，**需补失败矩阵或同等明确承诺**。
- **证据**：[应用失败策略 dispatch:719–733](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L719)；[recall失败 harness:190–208](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/harness.ts#L190)；[ingest与turn.completed:332–361](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/harness.ts#L332)；[Worldbook不可用测试:101–106](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/worldbook.test.ts#L101)；[后台模板同步准备 runtime:442–478](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L442)；[后台failed report:1028–1052](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L1028)；[Go memory调度:151–159](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/memory/axon-memory-runtime.ts#L151)；[Story catch返回报告:419–425](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/story/coordinator.ts#L419)、[dispatch仅await:1203–1206](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L1203)。

### 8. “安排后台”不等于可恢复持久任务，也不等于端到端一次成功

- **当前实现**：Emochi使用的BackgroundTaskRunner维护进程内Set<Promise>，创建内存signal和timer。源码中该runner没有持久队列、重启恢复记录、自动重放或按requestId的任务去重；coordinator.scheduled只去重单个实例内的一次调度。关闭时最多drain25秒后abort。Agentic schedule没有整任务timeout（undefined），每模型调用有自己的限时；observational planning timeoutSeconds=900不能当作总任务SLA。
- **业务影响**：不能承诺“提交后台即一定完成”“服务重启后自动接着做”“重复请求绝不额外推理”“后台900秒必完成/必终止”。外部DIO/图片服务可有自己的可靠性机制，但不能凭本地runner推断。若需要最终必达、去重计费、可追踪重试，要明确额外持久化/恢复责任。
- **原第 7 节是否修正**：四条均未保证这些性质，**不必改现有句子，但全面性必须补这一类运行保障**。
- **证据**：[runner内存队列 tasks:15–74](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/tasks.ts#L15)；[drain/abort:77–92](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/tasks.ts#L77)；[关闭25秒 dispatch:222–227](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L222)；[Agentic无总时限/900观测字段 runtime:558–595](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L558)。

## SDK 与工具层：权限、副作用、预算与观测

### 1. 工具注册、参数校验与用户权限/确认是不同层

**遗漏的产品判断：** “工具有注册、有 readOnly/idempotent 标签”不代表系统会自动授权、弹确认，或替业务拒绝危险副作用。

- **SDK 实现：** `AgenticCapabilityRegistry` 校验名字、重复项和 Schema；基础 registry 的 `validateArguments` 默认 `false`，而 `SlowTurnRuntime` 显式打开为 `true`。慢运行会在任何工具执行前校验整批调用；这是语法/能力边界，不是业务授权。
- `AgenticCapability` 只规定 `definition/advisory/execute`；`CapabilityMetadata` 的 `readOnly/idempotent/longRunning/streaming/cancellable` 是描述字段。Emochi `CapabilityExecutor` 直接调用已注册 capability，未按这些标签插入确认或权限决策。
- **Emochi 实际：** `StaticPlanner` 检查场景的 visibleCapabilities、依赖与环；普通闭环构造 `CapabilityExecutor([])`，由应用明确加入 Actor/工具链。Actor model/promptManager 另有配置白名单。因此“谁可调用什么”由具体场景、适配器和业务边界提供，不是 SDK 自动识别用户权限。
- 本次检索范围没有发现通用 `confirmation/approve` 人审状态机；这不等于仓库外调用方或 Pi 上游不能扩展，只能说当前 Harness 接线没有自动提供这一产品流程。

**应补的一句话：**“接入工具前必须明确场景白名单、用户权限、是否需要确认以及外部接口的校验；工具描述和 JSON Schema 不替代这些业务规则。”

证据：[packages/sdk/src/registry.ts:38–76](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/registry.ts#L38)；[packages/sdk/src/slow-runtime.ts:32–38,100–109](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/slow-runtime.ts#L32)；[packages/sdk/src/contracts.ts:251–254](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/contracts.ts#L251)；[packages/sdk/src/domain/contracts.ts:91–98](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/domain/contracts.ts#L91)；[apps/emochi/capabilities/executor.ts:60–72](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/capabilities/executor.ts#L60)；[apps/emochi/planning/static-planner.ts:14–46](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/static-planner.ts#L14)；[adapters/agent-router/dispatch.ts:1165–1172](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L1165)；[apps/emochi/integrations/roleplay-axon-adapter.ts:314–316](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/integrations/roleplay-axon-adapter.ts#L314)。

### 2. 状态提交不是附送数据库；三个“版本”不能混为一谈

**遗漏的产品判断：** 开发者需要实现/接入状态存储及并发控制，不能拿“返回 stateVersion 增加”当作导演状态已保存成功。

- **SDK 能力：** `AgenticStateStore` 只是 `get/compareAndSet` 接口，原子 revision/source-turn 校验及写前 abort 由 store 实现保证。SDK `prepareCommit` 可不提供；不提供就保持状态。提供后用起始 revision CAS，冲突报告 `stale_write_rejected`，不偷偷合并或覆盖。
- **Emochi 实际：** `AxonAgenticStateRuntime` 把用户/会话/场景身份绑定在宿主对象中，再调用 Axon state get/CAS。普通 Agentic 对完整候选做格式/变更验证，只有合格且 changed 才进入 CAS。
- `AgenticStateSnapshot.revision` 是 CAS 版本，`sourceTurn/historyRevision` 是来源位置，不是一个计数。
- **额外陷阱：** `TurnHarness` 成功路径的返回 `stateVersion` 只是 `request.stateVersion + 1`，不是读回的 Agentic CAS revision。因此不能据此给 UI 标“长期状态保存成功”。

**应补的一句话：**“明确区分请求完成版本、对话来源位置和每种状态的持久化 revision；只有对应 store 的提交结果证明那份状态写入成功。”

证据：[packages/sdk/src/contracts.ts:96–115,133–142](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/contracts.ts#L96)；[packages/sdk/src/slow-runtime.ts:148–181](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/slow-runtime.ts#L148)；[apps/emochi/planning/runtime.ts:84–135](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L84)；[apps/emochi/planning/agentic-v2.ts:968–988](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L968)；[apps/emochi/harness.ts:332](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/harness.ts#L332)。

### 3. 取消或报错不回滚外部效果；“完成”也不代表每个工具业务成功

**遗漏的产品判断：** 网络失败、用户停止、工具后处理失败后是否重新执行，会直接影响重复扣费/重复写入。

- **SDK 明确约定：** `SlowTurnRuntime.run` 注释指出：completed 可以包含 `ok:false` 工具结果；业务接受和重试属于调用方；取消结束等待但不能撤销外部写。
- `Tool.execute` 先 perform 再 afterExecute。如果 perform 已产生写入而 afterExecute 失败，整体仍会抛错，但不能重跑 perform。`Tool.afterTurn` 必须由宿主在整轮完成后显式调用，execute 不自动触发它；不能假设注册 hook 就有“一轮一次最终结算”。
- `createImageAssetTool` 和 `update_memory` 标记 `replay: "never"`。前者对未知生成结果明确要求不要自动重投，这个声明不等于库提供了一套跨进程去重数据库。
- **具体应用保障示例：** Sumi 图片生成先持久化 claim 再发送非幂等 image.generate；同一 message/index 的历史请求若结果未知，不静默再次发送；完成证据在调用方取消后仍尝试短时保存。这是 Sumi 自己的接线，不能泛化为所有 SDK 工具都有这个保障。

**应补的一句话：**“每个会写数据或收费的工具都需要自己的幂等/去重与结果不明策略；取消、失败、工具完成、业务成功是不同状态。”

证据：[packages/sdk/src/slow-runtime.ts:44–47](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/slow-runtime.ts#L44)；[packages/tools/src/tool.ts:10–13,16–34](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/tools/src/tool.ts#L10)；[packages/tools/src/image-tool.ts:71–88](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/tools/src/image-tool.ts#L71)；[packages/tools/src/memory-tool.ts:36](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/tools/src/memory-tool.ts#L36)；[apps/sumi/image-generation.ts:76–121](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/sumi/image-generation.ts#L76)。

读过的测试：[test/capability-executor.test.ts:63–70](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/test/capability-executor.test.ts#L63) 证明**执行前**取消不启动工具；`:73–83` 证明顺序模式遇 required 失败不启动后继。它们不证明已经启动的外部调用能被回滚。

### 4. 超时、上下文预算、调用次数、计费预算与重试是不同控制面

**遗漏的产品判断：** 配置了 timeout/maxCost 不代表用户一定在该时间收到完整结果，或绝不会产生任何超出预算的已发生费用。

- **SDK 默认慢路限额：** `maxSteps=4/maxToolCalls=8/maxParallelTools=4/timeoutMs=180000`；token 与 cost 上限是可选项。
- 慢路 `maxTotalTokens/maxCostUsd` 在调用开始前根据累计 usage 检查，并在模型返回 usage 后再次检查。它没有为并行调用预留预算，也不把剩余金额转为预付费限额；一次已经发出的模型调用可能使总量超过设定值，随后执行失败/停止后续调用。没有可用 usage/cost 时，启用相应预算会失败，而不是按零计算。
- SDK 的这些数字不是 Emochi 当前普通 Agentic 配置默认值；普通 Agentic 是自有 Planner，Actor 也有独立 retry 策略、目标模型、最大重试时间和整轮 signal。
- **Emochi 实际：** `TurnHarness` 设置整轮 deadline；Actor 瞬时重试要求尚未发出可见内容、上游错误可重试、未超次数/时间。普通 Agentic 又有自己的 model failure retries 与状态持久化失败处理。不能把所有重复请求归到一个统一 retryCount。

**应补的一句话：**“分别定义前台体验 SLA、慢路超时、模型调用/工具次数、上下文容量和成本预算；明确预算耗尽后的回复、降级与状态保留策略。”

证据：[packages/sdk/src/runtime-shared.ts:47–54,118–123](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/runtime-shared.ts#L47)；[packages/sdk/src/slow-runtime.ts:235–280](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/slow-runtime.ts#L235)；[apps/emochi/harness.ts:154–175](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/harness.ts#L154)；[apps/emochi/actor/roleplay-runtime.ts:759–762,1014–1016](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/actor/roleplay-runtime.ts#L759)；[apps/emochi/planning/agentic-v2.ts:102–159](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/agentic-v2.ts#L102)。

### 5. 后台 runner 不是持久任务队列；失败恢复必须另有宿主

**遗漏的产品判断：** “已安排后台处理”不能等同“即使服务重启，也保证最终完成”。

- **SDK 实现：** `BackgroundTaskRunner` 维护进程内 `Set<Promise<void>>`，提供 timeout/cancel/drain/abort；没有持久队列、租约、跨进程恢复或自动续跑记录。`FastSlowRuntime` 默认使用它，drain/shutdown 也只等待现有内存任务。
- **可接入能力：** `SlowTurnRuntime` 的设计是一个可 await 的慢轮次，宿主可以把它放入自己的 task/Workflow step；这是一条接入路径，不是当前 runner 自带 durable workflow。
- **Emochi 实际：** dispatch 创建共享 BackgroundTaskRunner；退出时先 drain 25 秒再 abort。这个优雅退出窗口提高了完成机会，但不能推导出进程崩溃后的任务必达。

**应补的一句话：**“如果产品要求记忆写入/状态分析必达，需明确持久调度、补偿和重启恢复责任；当前后台 Promise 调度本身不提供这项保证。”

证据：[packages/sdk/src/tasks.ts:15–17,23–75,77–92](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/tasks.ts#L15)；[packages/sdk/src/runtime.ts:48–57,74–85,126–132](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/runtime.ts#L48)；[packages/sdk/src/slow-runtime.ts:25,44–46](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/slow-runtime.ts#L25)；[adapters/agent-router/dispatch.ts:198,226–227](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L198)。

### 6. 角色、人设、记忆、聊天历史分别归不同服务/状态域

**遗漏的产品判断：** 若以后要做删除、换角色、复制会话、编辑历史或迁移用户，不能只迁一个“Memory”对象。

- **SDK 数据契约**含 character/userPersona/history/state，但不拥有角色后台或通用记忆数据库。
- **Emochi 实际角色来源：** RoleplayAxonAdapter 经 Axon 读 character card/model runtime，并通过 `buildSetVars` 按 userId/personaId/promptId 构建变量。角色定义、用户 persona、模型 preset/PromptManager 不是同一种状态。
- Agentic 状态以 user/conversation/scenario 绑定；Worldbook 使用独立书及 revision pin；日记/表通过所选 MemoryRuntime 与外部 hooks/Axon 操作；Hinos prepare/commit 是外部服务；Compact 使用自己的 checkpoint/覆盖范围。`get_memory/update_memory` 的可复用 JSON store 并未自动代替这套存储。
- **原始聊天保存边界：** 当前 Worldbook Demo BFF 显式在执行前保存 user、完成后保存 assistant；不能把这个 Demo 特有行为归为 SDK 自动保存所有聊天。
- 当前回复已经流式发出后，Memory ingest 仍可能失败；`failurePolicy.memoryIngest` 可选择 fail_turn 或 best_effort。这关系到 UI 是否显示已发送、是否让用户重试和是否重复生成，而不是纯日志细节。

**应补的一句话：**“列清每种数据的权威来源、作用域、读写方和生命周期；聊天完成、记忆落盘、状态提交需分别确认。”

证据：[packages/sdk/src/contracts.ts:184–209](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/contracts.ts#L184)；[apps/emochi/integrations/roleplay-axon-adapter.ts:318,377–394,640](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/integrations/roleplay-axon-adapter.ts#L318)；[apps/emochi/planning/runtime.ts:84–95](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L84)；[adapters/agent-router/dispatch.ts:797–871](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L797)；[apps/emochi/memory/hinos-memory-runtime.ts:50,112](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/memory/hinos-memory-runtime.ts#L50)；[apps/emochi/memory/compact-runtime.ts:1137](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/memory/compact-runtime.ts#L1137)；[apps/emochi/worldbook/debug-api.ts:153,175](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/worldbook/debug-api.ts#L153)；[packages/sdk/src/domain/contracts.ts:156–159](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/domain/contracts.ts#L156)；[apps/emochi/harness.ts:335–361](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/harness.ts#L335)。

### 7. 可观测、可回放、离线评估是不同能力，不能据此承诺自动质量闭环

**遗漏的产品判断：** “系统有 trace 和评估目录”不代表线上每轮都会自动判断剧情/记忆质量，或可以无副作用重放任意工具链。

- **SDK 观测：** slow_started/model/tool/commit/finished 事件，及可选 `HarnessTelemetry`/Langfuse backend；captureContent 默认关，redact 为可选注入；必须主动建立 run 并等待相关后台/业务提交，才能让其归入同一 run。观测失败不应改变业务控制流。
- **Emochi 实际：** 当前 apps/adapters 检索未见 `new HarnessTelemetry/createLangfuseTelemetry/FastSlowRuntime` 接线；普通 Agentic coordinator、后台任务等显式写 JSON stdout，TurnHarness 返回事件/trace，模型诊断另有 Kaon 路径。不能把 SDK 的可选 Langfuse API 描述成此应用已默认完整启用。
- **评估：** evaluations/runner 可指定目标/样例/次数执行生成并评分；通用 scorer 是 required/forbidden pattern 的规范化匹配，不是完整 RP 语义裁判。可用它查特定记忆召回/协议泄漏，但不能由通过率推断全部世界一致性正确。
- **回放：** Compact replay 明确是无网络的脚本计数/模型回复 fixture，用于机制回归，不能估计真实质量/时延/成本。Story 的确定性准备重放也不是任意带外部副作用工具的全局 replay guarantee。

**应补的一句话：**“先定义要观测与评估的业务结果，再分别接入线上诊断、持久审计和离线用例；观察到工具调用不等于验证剧情正确。”

证据：[packages/sdk/src/runtime-shared.ts:76–81](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/runtime-shared.ts#L76)；[packages/sdk/src/telemetry.ts:52–61,82–86,123–160](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/telemetry.ts#L52)；[packages/sdk/src/slow-runtime.ts:219–224](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/slow-runtime.ts#L219)；[packages/sdk/src/langfuse.ts:19,124](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/langfuse.ts#L19)；[adapters/agent-router/dispatch.ts:1159](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L1159)；[apps/emochi/harness.ts:102–130](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/harness.ts#L102)；[evaluations/runner.ts:55–80](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/evaluations/runner.ts#L55)；[evaluations/scorer.ts:12–43](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/evaluations/scorer.ts#L12)；[tests/integration/compact-replay.ts:29–34](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/tests/integration/compact-replay.ts#L29)。

### 8. “没有 contextPatch/director_notes”应限定到统一协议，不应否定现有当轮注入机制

**核查结论：** 第 7 节“没有独立通用的 contextPatch/director_notes 协议”作为**命名与统一协议**结论可以保留。本轮对 `packages/`、`apps/`、`adapters/` 的这两种 camel/snake 字段检索无命中；SDK SlowTurnResult 提供 final/toolResults，提交候选提供完整 state；普通 Agentic Director 输出完整 candidateState 并校验/CAS，均支持原判断。

**必须补足的限制：** 不应由此推导“所有工具结果只能先入 state 后一轮才给 Actor”。仓库已存在多条明确的当轮上下文扩展通路：

| 机制 | 输入/作用 | 实际层级 |
|---|---|---|
| `CapabilityOutput.promptContent` + `CapabilityNode.projectTo` | capability 结果按 foundation_context/turn_context 作为 system block 合入 prompt；projectTo=none 不注入 | domain 合约 + Emochi RPPromptCompiler；当前 ordinary dispatch 默认 executor 空，需实际接 capability |
| `nonCompressibleSystemMessages` | 当轮系统消息，参与 Compact 计数但不进入原始聊天历史 | Emochi AxonTurnPreparationOptions；Agentic 起始状态与 Story overlay 真实使用 |
| `ActorToolParameters.extraSetVars` / memory externalSetvars | 按既有模板变量机制影响本轮渲染 | Emochi RoleplayAxonAdapter |
| DIO `compiledPrompt` | 接受外部编译 prompt 后替换约定 roleplay/systemPrompt 槽位 | 指定 preActor/DIO 应用场景，不是慢路通用 director_notes |
| Worldbook blocks | 当轮按 position/depth/role 插入 Actor 消息 | 独立指定 Worldbook 场景 |

**建议把第 7 节第三条改为：**“SDK 没有统一的 contextPatch/director_notes 对象。普通 Agentic 后台走完整 state 候选、校验与 CAS，后续轮再读；但项目也有 capability promptContent、请求局部 system overlay、模板变量与 DIO/Worldbook 等当轮注入机制。接入时需明确采用哪条协议、影响哪一轮、是否持久化，以及谁进行预算与内容校验。”

证据：[packages/sdk/src/runtime-shared.ts:56–74,90–94](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/runtime-shared.ts#L56)；[packages/sdk/src/contracts.ts:230–235](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/contracts.ts#L230)；[packages/sdk/src/domain/contracts.ts:100–106,166–172](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/packages/sdk/src/domain/contracts.ts#L100)；[apps/emochi/prompt/compiler.ts:33–62](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/prompt/compiler.ts#L33)；[apps/emochi/ports.ts:40–52](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/ports.ts#L40)；[apps/emochi/planning/runtime.ts:338–361](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/planning/runtime.ts#L338)；[apps/emochi/story/axon-adapter.ts:87–88](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/story/axon-adapter.ts#L87)；[apps/emochi/integrations/roleplay-axon-adapter.ts:131–150,312,369–394](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/integrations/roleplay-axon-adapter.ts#L131)；[adapters/agent-router/dispatch.ts:763–774](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/adapters/agent-router/dispatch.ts#L763)；[apps/emochi/worldbook/runtime.ts:67–100](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/worldbook/runtime.ts#L67)。

## 世界书服务：内容生命周期与接入限制

### 1. 服务有管理 API，不代表当前 Demo 是世界书编辑器

**已确认：** 服务支持原生新建、批量导入和新修订；`/v1/imports/preview` 只解析并返回报告，不保存。当前 Harness Demo 则固定一本书的一个 revision，只放行 `book.get / book.entries / index.get` 三类读请求；预览、编辑、导入、重建索引和换书均不是该 Demo 的开放管理入口。

**PM 含义：** “后端支持导入／管理”与“用户现在可以在这个产品页面操作”必须分开验收；现有页面不能算完整作者工作台。

证据：[服务导入与保存 app.py 178–247](https://github.com/FlowGPT/worldbook-service/blob/3a11e333afd335aeff165e0ccc3654af8e1897d1/src/worldbook/app.py#L178)、[修订入口 app.py 281](https://github.com/FlowGPT/worldbook-service/blob/3a11e333afd335aeff165e0ccc3654af8e1897d1/src/worldbook/app.py#L281)、[Demo 固定版本和读方法白名单 demo-config.ts 30–48](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/worldbook/demo-config.ts#L30)、[预览拒绝 debug-api.ts 93](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/worldbook/debug-api.ts#L93)。

### 2. 可导入静态资料，不等于兼容整个 SillyTavern 运行时

**已确认：** 导入器识别 PNG／JSON；CCv2／CCv3 角色卡只提取 `character_book`，角色字段以 `character_fields_ignored` 警告说明被忽略；也接受独立 `world_info`。单次最多 5000 条。报告明确给出静态子集、源脚本不执行、全局 ST 设置不内嵌、非完整 ST 兼容等警告。EJS、前端／MVU、额外宏、sticky／cooldown／delay、部分分组／触发／位置逻辑等会被识别为运行时要求；不能把“文件解析成功”等同于“每条内容都可在当前选择器使用”。

另一个会直接改变召回效果的差异：原生 Entry 的 `exclude_recursion / prevent_recursion` 默认 true；导入器在源文件省略它们时默认 false。因此“递归默认关闭”不能覆盖所有导入路径。

**PM 含义：** 导入验收需要看报告、运行时受阻条目数和保存后的参数，不能只看成功条数；角色卡导入也不会顺便建立角色管理系统。

证据：[runtime 要求识别 importer.py 108–141](https://github.com/FlowGPT/worldbook-service/blob/3a11e333afd335aeff165e0ccc3654af8e1897d1/src/worldbook/importer.py#L108)、[导入递归默认值 186–187](https://github.com/FlowGPT/worldbook-service/blob/3a11e333afd335aeff165e0ccc3654af8e1897d1/src/worldbook/importer.py#L186)、[格式分支与限制 198–232](https://github.com/FlowGPT/worldbook-service/blob/3a11e333afd335aeff165e0ccc3654af8e1897d1/src/worldbook/importer.py#L198)、[报告 236–250](https://github.com/FlowGPT/worldbook-service/blob/3a11e333afd335aeff165e0ccc3654af8e1897d1/src/worldbook/importer.py#L236)、[原生默认 models.py 31](https://github.com/FlowGPT/worldbook-service/blob/3a11e333afd335aeff165e0ccc3654af8e1897d1/src/worldbook/models.py#L31)。

**未核验：** 各外部格式的完整字段保真矩阵、损失率、往返导出兼容性，不能在本次报告中宣称“完整支持”。

### 3. 修改书是在发布新版本；既有会话不会自动追最新版

**已确认：** PG 保存原文、不可变 revision 与 entries；修订使用 `expected_revision`，锁住当前书后匹配才新增版本、更新当前指针，否则 409。会话 pin 明确包含 `book_id + revision`。服务的新版本与会话何时改绑是两件事。Demo 会验证 pin 必须等于配置中的固定版本，旧 pin 不匹配时报错，不会悄悄迁移。

**PM 含义：** 作者“保存了修订”之后，需要产品另定生效范围：仅新会话、显式迁移旧会话，还是其他策略；当前不能承诺全部会话立即得到修改。

证据：[存储 repository.py 68](https://github.com/FlowGPT/worldbook-service/blob/3a11e333afd335aeff165e0ccc3654af8e1897d1/src/worldbook/repository.py#L68)、[修订 CAS 276](https://github.com/FlowGPT/worldbook-service/blob/3a11e333afd335aeff165e0ccc3654af8e1897d1/src/worldbook/repository.py#L276)、[创建会话时 pin debug-api.ts 104–114](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/worldbook/debug-api.ts#L104)、[版本不匹配拒绝 demo-config.ts 30–34](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/worldbook/demo-config.ts#L30)。

**未核验：** 线上版本迁移、历史版本保留时长、删除／回收策略。

### 4. 原文保存与索引 ready 是两个阶段；索引不是每轮自动补建

**已确认：** `POST /v1/books/{book_id}/index` 是显式同步构建请求，按书、revision、embedding version 加锁；ready 且未 force 时复用，状态变为 building → ready／failed。向量是同一 PG 中的可重建派生数据。换书版本不能凭旧 revision ready 就认定新版本也已就绪。

**PM 含义：** 导入成功不代表向量召回已经可用；需把索引状态、构建失败、强制重建和版本切换作为独立管理体验及运维事项。

证据：[索引入口 app.py 293](https://github.com/FlowGPT/worldbook-service/blob/3a11e333afd335aeff165e0ccc3654af8e1897d1/src/worldbook/app.py#L293)、[构建锁／复用 service.py 150–168](https://github.com/FlowGPT/worldbook-service/blob/3a11e333afd335aeff165e0ccc3654af8e1897d1/src/worldbook/service.py#L150)、[ready／failed 与写入 170–227](https://github.com/FlowGPT/worldbook-service/blob/3a11e333afd335aeff165e0ccc3654af8e1897d1/src/worldbook/service.py#L170)、[共用 PG vectors.py 97](https://github.com/FlowGPT/worldbook-service/blob/3a11e333afd335aeff165e0ccc3654af8e1897d1/src/worldbook/vectors.py#L97)。

**未核验：** 所有 embedding 配置变化的 fingerprint／失效判定矩阵、过期索引自动清理、部署时的自动预热。不能仅凭“按 embedding version 区分”推断这些都已实现。

### 5. 降级是特定分支，不是“世界书任何故障都不影响聊天”

**已确认：** rules 不需要向量；hybrid 的向量步骤遇到 `DomainError` 时标记 degraded，再继续词法排名；纯 vector 检索会抛错。Harness 空 pin 会直接产生空选择，但非空 pin 调用选条目 RPC 没有吞掉一般错误。资格、依赖、冲突和预算造成的失败也不能统称成“向量降级”。

**PM 含义：** 需要分别定义“向量不可用但可词法继续”和“世界书请求失败导致本轮回复不能开始”的产品行为。当前只有前一种明确回退路径。

证据：[向量前置条件 service.py 27](https://github.com/FlowGPT/worldbook-service/blob/3a11e333afd335aeff165e0ccc3654af8e1897d1/src/worldbook/service.py#L27)、[hybrid 降级分支 67–85](https://github.com/FlowGPT/worldbook-service/blob/3a11e333afd335aeff165e0ccc3654af8e1897d1/src/worldbook/service.py#L67)、[Harness 空 pin／RPC 错误传播 runtime.ts 49–64](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/worldbook/runtime.ts#L49)。

### 6. tenant 数据边界不能当成已经验收的请求鉴权

**已确认：** 当前 Worldbook `app.py` 普通接口取服务端 `settings.tenant_id`，该层没有检查 Bearer；还有 `/v1/admin` 只读跨租户浏览接口。当前实现与 README 的旧鉴权表述不一致。

**PM 含义：** 多租户字段、只读接口、请求身份验证是三个不同要求。不能在产品结论里直接写“用户访问已经按 token 隔离”，也不能据此断言线上服务公开无保护。

证据：[tenant 来源 app.py 32–33](https://github.com/FlowGPT/worldbook-service/blob/3a11e333afd335aeff165e0ccc3654af8e1897d1/src/worldbook/app.py#L32)、[admin 浏览接口 299](https://github.com/FlowGPT/worldbook-service/blob/3a11e333afd335aeff165e0ccc3654af8e1897d1/src/worldbook/app.py#L299)。

**未核验：** Axon 内部身份／租户转发、网关鉴权、网络隔离、生产部署入口；本次没有审查 Axon 仓库。这是覆盖范围限制，不是已证实的线上漏洞结论。

### 7. 世界书预算与完整模型预算是两道门，“常驻”也不保证入选

**已确认：** 服务默认 1500 token，当前 Harness 配置 2400；后者只管世界书部分。选择先 required、再可选 constant、再动态，连依赖整包取舍，长条目不切半；已过筛 required 包放不下会报错。常驻只是免关键词，仍受资格、冲突、预算约束。默认 35% 仅对可选 constant 发起包的新增成本计账，不是所有 constant 条目的绝对上限。

Harness 还对最终 Actor 输入计数：即使没有 Compact，只要有 worldbook，适配器也给出 `promptBudget` 和 1000 token 安全余量；Actor 检查模型总上下文扣掉输出 reserve 与余量后的空间，不足就报 `agent.context_overflow`。

**PM 含义：** “世界书选条目成功”不保证本轮完整 Prompt 能发出；“设为常驻／必需”也分别意味着候选与失败规则，不能用“永远放进模型”描述。

证据：[默认请求 models.py 119](https://github.com/FlowGPT/worldbook-service/blob/3a11e333afd335aeff165e0ccc3654af8e1897d1/src/worldbook/models.py#L119)、[整包预算 selection.py 237–289](https://github.com/FlowGPT/worldbook-service/blob/3a11e333afd335aeff165e0ccc3654af8e1897d1/src/worldbook/selection.py#L237)、[Worldbook 独立开启总预算 roleplay-axon-adapter.ts 556–561](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/integrations/roleplay-axon-adapter.ts#L556)、[完整计数与超限失败 roleplay-runtime.ts 842–874](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/actor/roleplay-runtime.ts#L842)。

### 8. 选中是程序判断，不是模型执行承诺；可解释结果也未全部永久留存

**已确认：** 选择是规则程序，hybrid 加词法与向量候选，不是聊天 LLM 读整本书做规划。关键词逻辑是激活途径，不是全局禁用条件：hybrid／显式依赖能绕开关键词路径，但仍要过资格过滤。默认扫描最近 4 条消息（含 query），不是每 4 轮触发。返回的 decisions／blocks 能解释本轮选择，却不保证模型逐条遵守，也不自动生成新条目或提交剧情状态。

Demo 的 worldbook trace 经 SSE 发给页面，当前服务端历史保存只落用户／助手正文；不能把页面可见调试快照当成跨浏览器、长期可追溯的审计存档。

**PM 含义：** “召回效果”“强制业务约束”“模型服从”“回放与审计”要分别验收。需要不可绕过的条件应使用资格规则；需要永久追踪则另定存储设计。

证据：[选择编排 service.py 122–148](https://github.com/FlowGPT/worldbook-service/blob/3a11e333afd335aeff165e0ccc3654af8e1897d1/src/worldbook/service.py#L122)、[资格、扫描与候选激活 selection.py 127–202](https://github.com/FlowGPT/worldbook-service/blob/3a11e333afd335aeff165e0ccc3654af8e1897d1/src/worldbook/selection.py#L127)、[本轮 trace runtime.ts 101–118](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/worldbook/runtime.ts#L101)、[SSE 与只保存正文 debug-api.ts 149–177](https://github.com/FlowGPT/roleplay-harness/blob/80aef3fa5582d8508ecdd1afa206391940ce9502/apps/emochi/worldbook/debug-api.ts#L149)。
