docs(planner): document plot history boundaries

This commit is contained in:
youzini
2026-06-09 17:07:39 +00:00
parent 0f1141969e
commit c0019eba43
4 changed files with 39 additions and 4 deletions

View File

@@ -28,11 +28,15 @@
召回输入按优先级解析(`resolveRecallInputController`override → 待发送意图send intent→ 聊天尾部用户楼层 → 已发送用户 → 最新用户楼层。
控制器里的来源/类型判定保持为小型纯 helperactive input source、no-new-user generation type、可信 user-floor source、持久复用输入构造分别独立测试。它们只做字符串规范化和布尔判定不调用 `retrieve()`、不写消息、也不触碰生成事务。
**持久召回复用有两条路径:**
1. **no-new-user 主路径**`reapplyPersistedRecallBlock`reroll / swipe / regenerate / continue 由宿主 `type` 判定为 no-new-user 后,`GENERATION_AFTER_COMMANDS` 不计算召回;`GENERATE_BEFORE_COMBINE_PROMPTS` 直接读取父 user 楼层的 `message.extra.bme_recall`,校验绑定文本未过期后确定性重放注入块。命中后不会进入 transaction / `runRecall` / 新检索。
2. **compute fallback 内部复用**`resolveReusablePersistedRecallRecord`):当主路径没有可用记录(例如无记录或陈旧)而落回 `runRecallController()` 时,如果当前输入匹配某条已持久化的用户楼层召回记录,可在控制器内复用已存注入内容,跳过新检索,返回 `llm.status="persisted"`
内部复用命中后,控制器只重写本次 effective recall input 的来源为 `persisted-user-floor`,并保留原 delivery mode / hook / source candidates 等上下文字段真正注入、generation count bump、metadata save 仍由原路径执行。
fresh `normal` 发送仍走正常输入选择与召回计算路径no-new-user 的父楼层绑定来自宿主生成上下文,而不是根据 textarea / send-intent 等输入源猜测(见 [`../architecture/control-plane.md`](../architecture/control-plane.md) 的 reroll 不变量)。
## 5. 向量预筛

View File

@@ -79,7 +79,8 @@
- `vector/vector-gate.js` — 向量准备/修复前置门禁,决定 skip / repair / blocked / sync。
- `runtime/generation-context.js` — 记录宿主本轮生成的 `type``normal` / `swipe` / `regenerate` / `continue` 等),并解析本轮应绑定的父 user 楼层。
- `runtime/reroll-recall-input.js` — 基于代际上下文构造召回输入;不再用一次性 marker 猜测 reroll。
- `runtime/reroll-recall-input.js` — 基于代际上下文构造召回输入,并保存 planner recall handoff / plot record handoff;不再用一次性 marker 猜测 reroll。
- `retrieval/recall-controller.js` — 召回控制器;来源/类型/持久复用输入构造是纯 helper检索执行和注入副作用仍留在控制器热路径里。
**reroll 不变量:**
@@ -96,6 +97,8 @@ no-new-user 的稳定路径分两段:
旧的召回事务机制仍保留为 fresh normal 和 fallback compute 的基础设施;它不再是 reroll 已存召回注入的唯一门闸。
ENA Planner 另有一条 plot record handoff它只负责把 planner 产出的剧情推进记录绑定到新 user 楼层的 `message.extra.st_bme_plot`,不参与召回决策。这样剧情历史持久化不依赖 planner recall 是否成功。
## 副本一致性模型
Authority 场景下有三处存储,它们**不是平级的版本副本**

View File

@@ -9,7 +9,7 @@ ST-BME 的测试是 Node 回归测试(`tests/*.mjs``npm run test:stable`
| 控制平面 | `identity-resolver` / `persistence-reducer` | 身份解析、持久化状态机不变量 |
| 数据格式 | `graph-snapshot-schema` / `graph-snapshot-upgrade` / `snapshot-forward-compat` | 快照契约、宽容解析、向前兼容往返 |
| 持久化 | `graph-persistence` / `indexeddb-*` | 图谱持久化、IndexedDB 快照/增量/hydrate |
| 检索/召回 | `p0-regressions` 内相关、`trivial-user-input` | 召回、reroll 复用、注入 |
| 检索/召回 | `p0-regressions` 内相关、`recall-controller-helpers``recall-reroll-reuse``trivial-user-input` | 召回来源判定、reroll 复用、注入 |
| 向量 | `vector-gate` / `vector-connection-probe` / `vector-sync-coalescer` | 向量门禁、连接探测、后台同步合并 |
| Native | `native-layout-parity` / `native-rollout-matrix` | native/JS 一致性、灰度门控 |
| 防线 | `index-slicing-ratchet` / `runtime-deps-completeness` / `i18n-user-visible-ratchet` | 见下 |
@@ -53,6 +53,7 @@ ST-BME 的测试是 Node 回归测试(`tests/*.mjs``npm run test:stable`
## 重要测试文件
- **`tests/p0-regressions.mjs`** — 主回归集合覆盖提取、召回、恢复、UI 关键路径。
- **`tests/recall-controller-helpers.mjs`** — 召回控制器的纯来源/类型/持久复用输入 helper。
- **`tests/runtime-history.mjs`** — 消息 hash、历史 dirty、恢复状态。
- **`tests/message-render-limit.mjs`** — 聊天区渲染限制和渲染切片历史保护。
- **`tests/graph-persistence.mjs`** — 图谱持久化基础行为。

View File

@@ -20,7 +20,7 @@ ENA Planner 是一个**可选的、发送前剧情规划**子系统。它独立
```
拦截发送(点击发送/回车)
→ 构建规划消息buildPlannerMessages
→ 收集上下文:角色卡 + BME 记忆召回 + 近期 AI 对话 + 历史 <plot> + 世界书 + 用户输入
→ 收集上下文:角色卡 + BME 记忆召回 + 近期 AI 对话 + 结构化/旧式 plot 历史 + 世界书 + 用户输入
→ 渲染模板/宏EJS、ST 宏)
→ 组装提示词块(优先用 planner 任务预设,回退遗留块)
→ 调用规划师 LLMcallPlanner可流式
@@ -34,10 +34,11 @@ ENA Planner 是一个**可选的、发送前剧情规划**子系统。它独立
## 与 ST-BME 的集成
ENA Planner 集成的是**召回**,不是提取:
ENA Planner 集成的是**召回**和**剧情历史记录**,不是提取:
- 它调用 BME 召回获取记忆块作为规划上下文(`runPlannerRecallForEna`)。
- 规划输出注入用户文本后,主生成会把规划标签当作用户消息的一部分看到。
- 规划输出会以结构化记录写入用户楼层 `message.extra.st_bme_plot`;后续规划优先读取这个记录,读不到时再回退扫描历史文本中的 `<plot>`
- 它**不**直接运行提取,也**不**把规划结果写进记忆图谱。后续提取走正常聊天/提取路径。
### 召回交接handoff
@@ -48,6 +49,32 @@ ENA Planner 集成的是**召回**,不是提取:
这套机制的实现见 `runtime/planner-recall-controller.js``runtime/reroll-recall-input.js``runtime/generation-recall-transactions.js`
### 结构化剧情历史
历史 plot 不再只依赖“从聊天文本里扫描 `<plot>`”。Planner 发送时会准备一条独立的 plot record handoff`MESSAGE_SENT` 绑定到新 user 楼层后写入:
```js
message.extra.st_bme_plot = {
version: 1,
rawUserInput,
plannerAugmentedMessage,
plotText,
plotBlocks,
inputHash,
createdAt,
recallHandoffId,
taskResults: []
}
```
读取顺序:
1. 优先读取 `message.extra.st_bme_plot` 中的结构化 `<plot>` 块。
2. 若结构化记录不足 `plotCount`,用历史消息文本里的旧式 `<plot>` 补足。
3. 只把 `<plot>` 内容喂回 planner`<note>` / `<state>` 等标签不会因为结构化记录而混入历史 plot 区。
plot record handoff 和 recall handoff 是两条独立通道:即使 planner 召回失败或被禁用,只要 planner 产出了 `<plot>`,剧情历史仍可持久化。这避免了“剧情推进记录依赖召回成功”的隐式耦合。
## 规划召回 vs 正常召回
| 维度 | 规划召回 | 正常召回 |