feat(rag): harden post-LightRAG runtime
Retire legacy OCR/media/evidence fallbacks, add local-folder event bus and Page Aggregate guards, and archive completed design checklists. Validation: cargo test -p mnote-web -- --test-threads=1; cargo test --workspace -- --test-threads=1; git diff --check; codegraph sync .; codegraph_status.
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
# 3-24 Local-folder browser event bus v1
|
||||
|
||||
> 创建时间:2026-06-07
|
||||
>
|
||||
> 状态:`done`
|
||||
>
|
||||
> Owner:03-rust-web / 05-editor-mainline / 07-ai
|
||||
>
|
||||
> 来源:`design/10-review/done/20-post-lightrag-runtime-hardening-checklist-v1.md` P2
|
||||
>
|
||||
> 上位依据:
|
||||
> - `design/03-rust-web/done/3-3-rust-web-tree-realtime-event-stream-v1.md`
|
||||
> - `design/03-rust-web/done/3-14-rust-web-tree-realtime-ws-push-v1.md`
|
||||
> - `design/03-rust-web/process/3-23-sidebar-local-folder-resource-runtime-followup-v1.md`
|
||||
|
||||
## 1. 第一结论
|
||||
|
||||
当前 local-folder 浏览器侧有多条独立刷新链:
|
||||
|
||||
- `tree-live-controller.js` 对 local-folder 使用 `/api/local-folder/events` EventSource,并派发 `tree:local-folder-watch-batch`。
|
||||
- `sidebar-tree-live-apply-runtime.js` 订阅 `tree:local-folder-watch-batch` 后刷新 filetree parent,必要时再刷新 sidebar projection。
|
||||
- `document-session-runtime.js` 也直接打开 `/api/local-folder/events`,用于当前文档内容刷新。
|
||||
- `document-resource-tab-runtime.js` 对资源 tab 直接打开 `/api/local-folder/events`,并在部分保存后合成 `tree:local-folder-watch-batch`。
|
||||
- `sidebar-page-ai-runtime.js` 从 agent receipt 合成 `tree:local-folder-watch-batch` 与 `mnote:page-ai-tool-write-completed`。
|
||||
|
||||
这会造成同一 `workspaceId/rootUri` 页面内多个 EventSource、receipt + watcher echo 双刷新、sidebar projection 和 filetree parent 重复请求。P2 不改 Rust watcher 协议,先在浏览器侧增加单例 event bus,把连接、事件归一、订阅和刷新编排收口。
|
||||
|
||||
## 2. 非目标
|
||||
|
||||
- 不改变 `/api/local-folder/events`、`/api/realtime/ws`、`/api/tree/events` 的服务端协议。
|
||||
- 不在本稿恢复轮询 fallback。
|
||||
- 不把 event bus 变成新的树/文件/文档事实源;它只转发和归一事件。
|
||||
- 不一次性重写 sidebar、document session、resource tab、Page AI runtime;按订阅方逐步切换。
|
||||
- 不改变 Page AI agent 文件编辑的 audit / receipt 语义。
|
||||
|
||||
## 3. 输入源
|
||||
|
||||
统一入口:新增 `rust/crates/mnote-web/browser/local-folder-event-bus-runtime.js`,挂到 `window.__mnoteLocalFolderEventBus`。
|
||||
|
||||
输入源:
|
||||
|
||||
- `watcher_sse`:`/api/local-folder/events?rootUri=...&treeLive=true`,当前 local-folder 主输入。
|
||||
- `tree_ws`:`/api/realtime/ws`,只在非 local-folder tree live 或未来 local-folder WS 化时接入。
|
||||
- `tree_sse`:`/api/tree/events`,作为 tree projection fallback,不直接替代 local-folder watcher。
|
||||
- `synthetic_page_ai_receipt`:Page AI receipt 合成事件。
|
||||
- `synthetic_resource_write`:resource tab 保存后合成事件。
|
||||
- `explicit_resync`:命令结果或 runtime 主动要求重新取 sidebar/filetree/document。
|
||||
|
||||
约束:
|
||||
|
||||
- 同一 `workspaceId/rootUri` 页面内只允许一个 local-folder watcher 连接。
|
||||
- bus 连接 key 以页面内 `rootUri` 为准;`workspaceId` 只作为事件元信息。原因是 tree live bootstrap、document session、resource tab 在 local-folder 页面可能分别拿到空 workspaceId / local-ws workspaceId,若把 workspaceId 放入连接 key 会在同一 rootUri 内重复建 watcher。
|
||||
- 不同 rootUri 可以有不同 bus instance;默认页面只注册当前 rootUri。
|
||||
- bus 输出事件必须带 `source`、`reason`、`rootUri`、`workspaceId`、`revision`、`changedPaths`、`affectedParents`。
|
||||
|
||||
## 4. 输出事件
|
||||
|
||||
bus 派发浏览器事件:
|
||||
|
||||
- `mnote:local-folder:event-bus-ready`
|
||||
- `mnote:local-folder:watch-batch`
|
||||
- `mnote:local-folder:document-changed`
|
||||
- `mnote:local-folder:resource-changed`
|
||||
- `mnote:local-folder:filetree-parent-changed`
|
||||
- `mnote:local-folder:knowledge-rag-source-updated`
|
||||
- `mnote:local-folder:resync-required`
|
||||
|
||||
兼容桥:
|
||||
|
||||
- 短期继续派发旧 `tree:local-folder-watch-batch`,但 detail 增加 `viaEventBus=true`。
|
||||
- 短期继续派发旧 `mnote:page-ai-tool-write-completed`,document session 可逐步改订阅新事件。
|
||||
|
||||
## 5. 订阅方职责
|
||||
|
||||
- Sidebar / FileTree:
|
||||
- 订阅 `filetree-parent-changed` 刷新局部 parent。
|
||||
- 订阅 `resync-required` 刷新 sidebar projection。
|
||||
- 不直接拥有 watcher 连接。
|
||||
- Document session:
|
||||
- 订阅 `document-changed`,仅当当前文档路径命中才刷新当前 buffer。
|
||||
- 不因任意 watch batch 刷新当前文档。
|
||||
- Resource tab:
|
||||
- 订阅 `resource-changed`,仅当当前资源路径命中才刷新 stat/read。
|
||||
- resource save 完成后只向 bus 发 synthetic event,不直接广播全局 watch batch。
|
||||
- Page AI:
|
||||
- receipt 只向 bus 发 `synthetic_page_ai_receipt`。
|
||||
- 由 bus 去重 watcher echo 与 receipt refresh,避免重复 sidebar projection。
|
||||
- Knowledge RAG UI:
|
||||
- 订阅 `knowledge-rag-source-updated`,只刷新资料库来源状态,不触发文档正文刷新。
|
||||
|
||||
## 6. 实施 Checklist
|
||||
|
||||
Phase A:只加 bus,不切换行为。
|
||||
|
||||
- [x] 新增 `local-folder-event-bus-runtime.js`。
|
||||
- [x] 在 SSR layout 中加载 bus runtime,保证早于 tree live controller;document session / resource tab 后续切订阅时继续复用该入口。
|
||||
- [x] bus 可以接管 `tree-live-controller.js` local-folder EventSource 创建;同一 rootUri 二次 start 返回同一连接。
|
||||
- [x] bus 继续兼容派发 `tree:local-folder-watch-batch`,并标记 `viaEventBus=true`。
|
||||
- [x] DOM diagnostics:
|
||||
- `data-mnote-local-folder-event-bus="ready"`
|
||||
- `data-mnote-local-folder-event-bus-connections`
|
||||
- `data-mnote-local-folder-event-bus-last-source`
|
||||
- `data-mnote-local-folder-event-bus-last-reason`
|
||||
|
||||
Phase A 结果:
|
||||
|
||||
- 新增 `/api/mnote-browser-runtime/local-folder-event-bus-runtime.js` runtime asset。
|
||||
- `tree-live-controller.js` 的 local-folder 分支优先调用 `window.__mnoteLocalFolderEventBus.startLocalFolderWatcher(...)`;bus 不可用时保留原 `/api/local-folder/events` 直连 fallback。
|
||||
- bus 连接 key 已按 `rootUri` 收口,避免 tree live / resource tab 因 workspaceId 解析差异重复建连接。
|
||||
- 当前只收敛 tree live controller 的 local-folder watcher;`document-session-runtime.js` 与 `document-resource-tab-runtime.js` 仍在 Phase C 切换,P2 总体验收尚未完成。
|
||||
|
||||
Phase B:刷新编排。
|
||||
|
||||
- [x] `refreshLocalFolderSidebarSnapshot` 外包到 bus orchestrator:同一 tick 合并 reason 和 parent 列表。
|
||||
- [x] bus 维护 `pendingFileTreeParents`,同一 parent 在同一 tick 只刷新一次。
|
||||
- [x] fallback / resync 仍允许刷新 sidebar projection,但必须记录 reason。
|
||||
- [x] `sidebar-tree-live-apply-runtime.js` 由直接处理 watch batch 改为订阅 bus 输出。
|
||||
|
||||
Phase B 结果:
|
||||
|
||||
- bus 新增 `mnote:local-folder:sidebar-refresh-requested`,同一 tick 合并 `changedPaths`、`affectedParents`、`reasons` 和 `resyncRequired`。
|
||||
- `sidebar-tree-live-apply-runtime.js` 订阅 `mnote:local-folder:sidebar-refresh-requested` 后复用 `applyLocalFolderWatchBatch(...)`,并跳过 `viaEventBus=true` 的旧 `tree:local-folder-watch-batch` 兼容事件,避免同一 bus 事件被 sidebar 处理两次。
|
||||
- `task540` 会连续发两次同 tick `synthetic_page_ai_receipt`,验证最终只产生一次 filetree parent projection 请求,且 content-only receipt 不触发 sidebar projection。
|
||||
|
||||
Phase C:订阅方切换。
|
||||
|
||||
- [x] `document-session-runtime.js` 不再直接打开 `/api/local-folder/events`;改订阅 `document-changed`。
|
||||
- 正常 bus 可用路径已改订阅 `mnote:local-folder:document-changed` 并复用 `startLocalFolderWatcher(...)`;保留 bus 不可用时旧 EventSource fallback,作为退路而非主路径。
|
||||
- [x] `document-resource-tab-runtime.js` 不再为每个 resource tab 直接打开 EventSource;改订阅 `resource-changed`。
|
||||
- passive resource tab 已在 bus 可用时订阅 `mnote:local-folder:resource-changed`,并以 `data-mnote-resource-watch-ready="event-bus"` 暴露诊断;保留 bus 不可用时旧 EventSource fallback。
|
||||
- [x] resource write 完成后向 bus 发 `synthetic_resource_write`。
|
||||
- [x] Page AI receipt 向 bus 发 `synthetic_page_ai_receipt`。
|
||||
|
||||
Phase D:smoke。
|
||||
|
||||
- [x] 新增 `task540-local-folder-event-bus-single-connection-smoke.js`。
|
||||
- [x] 同一页面打开 sidebar + document + resource tab + Page AI 后,只存在一个 local-folder watcher EventSource。
|
||||
- Phase D-1:`task540` 当前覆盖 sidebar/tree live + document session 同页只创建一个 `/api/local-folder/events` EventSource,并验证 synthetic event 兼容派发带 `viaEventBus=true`;resource tab + Page AI 全组合请求计数仍待后续扩展。
|
||||
- Phase D-2:`task540` 已扩展到 passive resource tab,并验证 resource tab watch ready 走 `event-bus`、`synthetic_page_ai_receipt` 事件经 bus 派发、同页仍只有一个 `/api/local-folder/events` EventSource。尚未覆盖真实 Page AI 面板点击到 receipt 的完整 UI 链路。
|
||||
- [x] 外部修改当前 `.md` 后,tiptap 可见刷新。
|
||||
- [x] 外部新增 / 删除文件后,filetree 只刷新受影响 parent。
|
||||
- [x] Page AI receipt 后,sidebar projection 不重复请求。
|
||||
- [x] 复跑 `task446`、`task447`、`task448` 或相邻 tree realtime smoke。
|
||||
- `task446` / `task447` / `task448` 当前仍依赖无 workspace 的 `/api/tree/commands` cloud/Convex 旧入口,运行结果为 `convex_retired`,不适合作为 local-folder event bus 验收证据。
|
||||
- 已改用相邻 local-folder runtime smoke:`task435`、`task436`、`task535`、`task540`。
|
||||
|
||||
Phase C-1 / D-1 结果:
|
||||
|
||||
- `document-session-runtime.js` 在 event bus 可用时不再新建按 documentId/resourcePath 分裂的 EventSource,改为共享 root 级 bus 并按 documentId / relativePath 过滤。
|
||||
- passive `document-resource-tab-runtime.js` 在 event bus 可用时改订阅 `resource-changed`,旧 per-resource EventSource 仅作为 fallback。
|
||||
- `document-resource-tab-runtime.js` 的 local OCR sidecar refresh 改为优先 `synthetic_resource_write` 发给 bus,旧 `tree:local-folder-watch-batch` 只作为 bus 不可用 fallback。
|
||||
- `sidebar-page-ai-runtime.js` 的 agent receipt refresh 改为优先 `emitSyntheticWatchBatch(...)`,兼容事件由 bus 统一派发。
|
||||
- 扩展 `task540` 后发现同 rootUri 下 tree live 与 resource tab 的 workspaceId 解析差异会导致重复连接;已把 bus 连接 key 收口为 `rootUri`,`workspaceId` 只作为事件元信息。
|
||||
- `task540` 在 3300 最新 mnote-web 通过,验证当前文档页 + passive resource tab 只创建一个 local-folder watcher EventSource、bus diagnostics ready、`synthetic_page_ai_receipt` source/reason 保留、兼容事件带 `viaEventBus=true`,且 resource-changed 触发当前资源 stat 刷新。
|
||||
- `task535` 在 3300 最新 mnote-web 通过,验证真实 Page AI clean agent receipt 后当前文档和 filetree 均刷新,且不调用旧保存/写入工具。
|
||||
- `task436` 在 3300 最新 mnote-web 通过,验证当前打开 local `.md` 外部修改后 tiptap 可见刷新,并覆盖 dirty 冲突保护。
|
||||
- `task435` 在 3300 最新 mnote-web 通过,验证外部创建/重命名/删除 Markdown 与非 Markdown 资源后 page tree / filetree 原地更新且无 reload。
|
||||
|
||||
## 7. 验收与归档条件
|
||||
|
||||
- 页面内同一 `workspaceId/rootUri` 只有一个 local-folder watcher 连接。
|
||||
- sidebar、document session、resource tab、Page AI receipt 都通过 event bus 收敛。
|
||||
- `tree:local-folder-watch-batch` 兼容事件仍可用,但 detail 标明 `viaEventBus=true`。
|
||||
- P2 smoke 全部通过,并记录请求计数证据。
|
||||
- 本稿完成后移动到 `design/03-rust-web/done/`。
|
||||
@@ -0,0 +1,48 @@
|
||||
# 5-36 Page Aggregate local-first hard guard v1
|
||||
|
||||
> 创建时间:2026-06-07
|
||||
>
|
||||
> 状态:`done`
|
||||
>
|
||||
> Owner:05-editor-mainline
|
||||
>
|
||||
> 上位 checklist:`design/10-review/done/20-post-lightrag-runtime-hardening-checklist-v1.md` P3
|
||||
|
||||
## 1. 目标
|
||||
|
||||
防止 local-first `.md` 文档页静默回落到 `compat.legacy_content` 影子正文路径。local folder 的正常读链必须是:
|
||||
|
||||
1. 本地 Markdown 文件是真相。
|
||||
2. Rust Page Aggregate 输出 `body.projectionSource=local_markdown.content`。
|
||||
3. Page Aggregate 输出 `body.blockDocument`。
|
||||
4. 浏览器 tiptap runtime 优先消费 `page_aggregate.block_document`。
|
||||
|
||||
## 2. 非目标
|
||||
|
||||
- 不删除 cloud / legacy / explicit compat 的 `compat.legacy_content` fallback。
|
||||
- 不改写 Page Aggregate 保存命令族。
|
||||
- 不扩大 legacy blocks / `documents.content` 的 local-first 使用面。
|
||||
|
||||
## 3. Checklist
|
||||
|
||||
- [x] 复核 `document-tiptap-conversion-runtime.js` source 判定:`blockDocument` 优先于 `content`。
|
||||
- [x] 给文档 editor root 增加 DOM diagnostic:
|
||||
- `data-mnote-page-body-source`
|
||||
- `data-mnote-page-body-local-compat-fallback`
|
||||
- `data-mnote-page-body-hard-guard`
|
||||
- [x] local-first browser smoke 断言 `.md` 文档页为 `page_aggregate.block_document`,且 `local-compat-fallback=false`。
|
||||
- [x] `task522` contract 保留 explicit compat fallback 正例。
|
||||
- [x] `task167` API smoke 继续证明 local-first Page Aggregate 输出 `local_markdown.content` + `blockDocument`。
|
||||
|
||||
## 4. 验证结果
|
||||
|
||||
- `node scripts/task522-page-aggregate-compat-fallback-contract.js` 通过。
|
||||
- `node scripts/task167-local-markdown-title-body-options-no-convex-smoke.js` 通过。
|
||||
- `node scripts/task541-page-aggregate-local-first-hard-guard-smoke.js` 通过:真实浏览器打开 local `.md`,editor root 诊断为 `data-mnote-page-body-source=page_aggregate.block_document`、`data-mnote-page-body-local-compat-fallback=false`、`data-mnote-page-body-hard-guard=local_ok`。
|
||||
- `cargo test -p mnote-web document_editor_adapter_runtime_contains_host_contracts -- --test-threads=1` 通过。
|
||||
|
||||
## 5. 归档条件
|
||||
|
||||
- [x] `design/10-review/done/20-post-lightrag-runtime-hardening-checklist-v1.md` P3 全部勾选。
|
||||
- [x] P3 targeted smoke 和 contract test 通过。
|
||||
- [x] CodeGraph 同步无 pending。
|
||||
+7
-3
@@ -2,7 +2,7 @@
|
||||
|
||||
> 创建时间:2026-06-06
|
||||
>
|
||||
> 状态:`process`
|
||||
> 状态:`done`
|
||||
>
|
||||
> Owner:07-ai / 05-editor-mainline / 03-rust-web
|
||||
>
|
||||
@@ -117,7 +117,7 @@ Checklist:
|
||||
验收:
|
||||
|
||||
- [x] `cargo test -p mnote-web local_agent_audit -- --test-threads=1` 或等价 targeted tests 通过。
|
||||
- [ ] clean smoke 中 audit snapshot 只包含目标文件及必要 changed file。
|
||||
- [x] clean smoke 中 audit snapshot 只包含目标文件及必要 changed file。
|
||||
|
||||
## 8. Phase E:文档与 manifest 退役口径
|
||||
|
||||
@@ -133,7 +133,11 @@ Checklist:
|
||||
验收:
|
||||
|
||||
- [x] `7-18-local-first-agent-file-editing-control-plane-v1.md` Phase B/C 可勾选。
|
||||
- [ ] 本 checklist 可移动到 `design/07-ai/done/`,父设计 `7-18` 仅剩跨 workspace / 多 target 的产品确认项。
|
||||
- [x] 本 checklist 可移动到 `design/07-ai/done/`,父设计 `7-18` 仅剩跨 workspace / 多 target 的产品确认项。
|
||||
|
||||
补充证据:
|
||||
|
||||
- 2026-06-07:`task539-local-agent-audit-scope-contract.js` 复跑 `task535` 并断言 `targetPackage.allowedFiles=["AgentClean.md"]`、`runTargetSnapshot.frozenAt` 存在、未调用 `/api/documents/save` / `mnote.doc.markdown_edit` / `mnote.page.save`;同时运行 `cargo test -p mnote-web local_agent_audit -- --test-threads=1`,覆盖 `auditScope.scope=allowed_files` 与 `fileCount=1`。
|
||||
|
||||
## 9. 推荐执行顺序
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
# 7-51 LightRAG post-commit hardening v1
|
||||
|
||||
> 创建时间:2026-06-07
|
||||
>
|
||||
> 状态:`done`
|
||||
>
|
||||
> Owner:07-ai / knowledge-rag / 03-rust-web / plugin-ui
|
||||
>
|
||||
> 来源:`design/10-review/done/20-post-lightrag-runtime-hardening-checklist-v1.md` P0 审计
|
||||
>
|
||||
> 上位依据:
|
||||
> - `design/07-ai/done/7-50-lightrag-knowledge-rag-provider-v1.md`
|
||||
> - `design/10-review/done/20-post-lightrag-runtime-hardening-checklist-v1.md`
|
||||
|
||||
## 1. 第一结论
|
||||
|
||||
7-50 作为 LightRAG 资料库问答主线可以保持 `done`,但 post-commit audit 发现若干需要单独硬化的边界:
|
||||
|
||||
- watcher stale sync 在 best-effort 删除失败时会吞掉错误,并且已经清空 registry 中的 `lightRagDocId`,后续难以重试删除 provider orphan doc。
|
||||
- `sourcePaths` 当前是 provider 检索后过滤 MNote mapped references,不是 provider 预过滤;HTTP API 仍返回未过滤 `raw`,存在调用方误用 raw 的风险。
|
||||
- sidecar locator 在 quote 未命中时会 fallback 到 `first_positioned_block`,可能生成错误 page/bbox,却表现为非 degraded locator。
|
||||
- `mnote-knowledge-rag` skill 文案对 degraded citation 过强,容易让 agent 误以为不能使用返回的降级 resourceTab 链接。
|
||||
- Reasonix wrapper 仍手写工具表,能力注册漂移问题还没有真正解决。
|
||||
|
||||
本稿不恢复旧 evidence / LiteParse / local OCR 路径,不开发第二套 RAG,只硬化 7-50 已选定的 LightRAG provider 边界。
|
||||
|
||||
## 2. 非目标
|
||||
|
||||
- 不重建 `mnote.evidence.*` / `mnote.index.*` agent 工具。
|
||||
- 不把 source scope 伪装成 LightRAG provider 原生过滤,除非实际实现了 provider 级约束。
|
||||
- 不清空用户资料库、不删除用户原始 source、不自动大规模 reindex。
|
||||
- 不把 LightRAG sidecar / chunk / graph 当作 MNote 正文真相。
|
||||
- 不在本稿内实施完整 capability registry;只补必要漂移测试或文案约束,完整 registry 仍按 `7-47` / `20 P4` 推进。
|
||||
|
||||
## 3. Phase A:Delete retry / orphan doc guard
|
||||
|
||||
目标:source 删除或 hash 变化后,即使 LightRAG 删除失败,也不能丢失重试 provider doc id;prune 不能隐藏仍可能参与回答的 orphan doc。
|
||||
|
||||
Checklist:
|
||||
|
||||
- [x] 修改 `sync_registry_source_state(...)`:source missing / hash changed 时不要立即清空 `lightRagDocId`;应进入 `stale=true` + `lightRagStatus=delete_submitted` 或 `delete_retry_required`。
|
||||
- [x] `sync_registry_with_documents(...)` 调用 LightRAG delete 失败时,把失败写入 registry entry 的可见状态,而不是吞掉后只保留 stale。
|
||||
- [x] 只有确认 LightRAG `/documents` 不再包含该 doc 后,才清空 `lightRagDocId` 并标记 `delete_completed`。
|
||||
- [x] `prune_registry` 不清理仍带 `lightRagDocId` 且 delete 未确认完成的 stale entry。
|
||||
- [x] `mapped_references(...)` 对 missing registry 的 provider reference 需要区分:
|
||||
- provider orphan / unknown source:默认不作为有效 MNote citation 返回,或明确返回 degraded + unmapped 分类,但不得进入 scoped answer citation。
|
||||
- registry 命中但 stale / deleted:继续过滤。
|
||||
- [x] 对 `delete-source` route 保持 `delete_file=false`,并保留“不删除用户原始 source”的断言。
|
||||
|
||||
验证:
|
||||
|
||||
- [x] 单测:LightRAG delete 失败时 registry 保留 doc id 和 retry 状态。
|
||||
- [x] 单测:delete completed 后才清 doc id。
|
||||
- [x] 单测:prune 不删除 `delete_submitted` / `delete_retry_required` entry。
|
||||
- [x] 单测:missing registry provider reference 不会作为正常 citation 返回。
|
||||
- [x] `cargo test -p mnote-web knowledge_rag -- --nocapture`
|
||||
|
||||
实施记录:
|
||||
|
||||
- 2026-06-07:`sync_registry_source_state(...)` 在 source missing / hash changed 时保留 `lightRagDocId`,并把状态置为 `delete_submitted`。
|
||||
- 2026-06-07:`sync_registry_with_documents(...)` 会重试 `delete_submitted` / `delete_retry_required` doc id;LightRAG delete 失败时写入 `delete_retry_required`,成功提交后保持 `delete_submitted`,等 `/documents` 消失后才标记 `delete_completed` 并清空 doc id。
|
||||
- 2026-06-07:当前 registry schema 先用 `lightRagStatus=delete_retry_required` 表达失败状态,不额外扩写错误 message 字段,避免扩大持久化迁移面。
|
||||
|
||||
## 4. Phase B:Source scope 语义收紧
|
||||
|
||||
目标:避免调用方误以为 `sourcePaths` 已限制 LightRAG provider 检索范围。
|
||||
|
||||
Checklist:
|
||||
|
||||
- [x] 在 `/api/knowledge-rag/query` 返回中新增 `sourceScopeMode`,当前值明确为 `post_filter_mapped_references`。
|
||||
- [x] 若 `sourcePaths` 非空,默认不向普通 agent / Page AI 暴露未过滤 `raw` chunks;至少 compact tool output 继续不暴露 raw chunks。
|
||||
- [x] HTTP API 如仍保留 `raw`,必须标注 `rawScopeFiltered=false` 或等价字段,提醒 raw 未受 source scope 过滤。
|
||||
- [x] `mnote.knowledge_rag.query` manifest / Reasonix wrapper / skill 文案从“限制检索来源”改为“按 MNote source 过滤返回 references;provider raw 可能仍为全局检索结果”。
|
||||
- [x] Page AI final answer 只允许引用 filtered `references/citations`,不得引用 raw LightRAG chunks。
|
||||
|
||||
验证:
|
||||
|
||||
- [x] 单测:`sourcePaths=[alpha]` 时 `references` 只含 alpha。
|
||||
- [x] 运行态 smoke:`sourceScopeMode=post_filter_mapped_references` 且 `rawScopeFiltered=false`。
|
||||
- [x] 单测或 wrapper selftest:agent compact result 不含 raw chunks。
|
||||
- [x] `task538-knowledge-rag-source-scope-api-smoke.js` 更新并通过。
|
||||
- [x] `task534-knowledge-rag-source-management-scope-smoke.js` UI source management 部分已修复并通过。
|
||||
|
||||
实施记录:
|
||||
|
||||
- 2026-06-07:`/api/knowledge-rag/query` 返回 `sourceScopeMode=post_filter_mapped_references` 与 `rawScopeFiltered=false`。
|
||||
- 2026-06-07:`mnote.knowledge_rag.query` compact agent result 继续只暴露 filtered `references/citations`,不暴露 `raw.chunks`。
|
||||
- 2026-06-07:manifest、Reasonix wrapper、`skills/mnote-knowledge-rag/SKILL.md` 已统一 sourcePaths post-filter 口径;新增 `task538-knowledge-rag-source-scope-api-smoke.js` 覆盖 API scope metadata、filtered references、`delete-source` 不删原始 source。
|
||||
- 2026-06-07:`task534` 修正为打开资料库设置后切到“全部”来源,避免默认“需处理”过滤隐藏已索引 source;在 3300 最新构建通过。
|
||||
|
||||
## 5. Phase C:Locator strict match / degradation
|
||||
|
||||
目标:没有真实匹配到 quote / chunk 对应 sidecar block 时,不生成看似精确的 page/bbox。
|
||||
|
||||
Checklist:
|
||||
|
||||
- [x] 修改 `find_lightrag_sidecar_block(...)`:移除或限制 `first_positioned_block` fallback;只有 quote 与 block content 达到明确匹配阈值时才返回 page/bbox locator。
|
||||
- [x] 若只找到 source resource 但没有精确 block match,返回 clickable degraded resourceTab citation,但 `locatorDegraded=true`。
|
||||
- [x] `citationMarkdown` 对 degraded resourceTab 使用稳定文案,例如 `来源定位降级:<file>`,不包含伪造页码。
|
||||
- [x] 对 PDF / image / DOCX fallback citation 分别保留打开能力,但不伪造 bbox。
|
||||
- [x] 记录 LightRAG chunk 缺 `refs` 的当前边界;未来若 provider 暴露 refs,再改为 refs 优先、文本匹配 fallback。
|
||||
|
||||
验证:
|
||||
|
||||
- [x] 单测:quote 不匹配 sidecar block 时不返回 page/bbox locator。
|
||||
- [x] 单测:quote 匹配 sidecar block 时仍返回 page/bbox locator。
|
||||
- [x] 单测:known resource + no locator 返回 clickable degraded citation。
|
||||
- [x] `task529-knowledge-rag-citation-resource-tab-smoke.js` 更新为当前 fixture 可重复的正例,并通过。
|
||||
|
||||
实施记录:
|
||||
|
||||
- 2026-06-07:`find_lightrag_sidecar_block(...)` 已移除 `first_positioned_block` fallback;未匹配 quote 时返回降级 resourceTab citation,不生成 page / bbox。
|
||||
- 2026-06-07:当前 LightRAG `/query/data` chunks 未提供可稳定回跳 MNote sidecar block 的 provider `refs`;MNote 暂以文本匹配做严格定位,未匹配时只给 degraded resourceTab。
|
||||
- 2026-06-07:`task529` 改为当前 image source 降级 citation 正例,验证 `open_reference` 与 citation URL 能打开 image resource tab,且不携带伪造 page locator。
|
||||
|
||||
## 6. Phase D:Agent / UI degraded citation 口径统一
|
||||
|
||||
目标:agent 可以使用 MNote 返回的 degraded citation,但不能编造页码、bbox 或 provider 内部路径。
|
||||
|
||||
Checklist:
|
||||
|
||||
- [x] 更新 `skills/mnote-knowledge-rag/SKILL.md`:`locatorDegraded=true` 时,可以引用返回的 `citationMarkdown`,但必须说明来源定位降级;禁止编造 page / bbox。
|
||||
- [x] 更新 Reasonix system prompt 中 knowledge-rag 能力说明,保持同一口径。
|
||||
- [x] 更新 Page AI final answer smoke,增加 degraded citation 场景:最终回答可以含降级 citation,但不能说成 p.N / bbox。
|
||||
- [x] 更新 dashboard smoke,不再依赖固定 `Completed (5)` / `Fail (4)` / 固定 doc id;改为验证 Documents / Graph / Retrieval 入口与当前 documents summary 可见。
|
||||
|
||||
验证:
|
||||
|
||||
- [x] `MNOTE_REASONIX_ACP_SELFTEST=1 node scripts/reasonix-acp-wrapper.mjs`
|
||||
- [x] `node scripts/task530-knowledge-rag-page-ai-final-answer-smoke.js`
|
||||
- [x] `node scripts/task531-lightrag-dashboard-ui-smoke.js`
|
||||
|
||||
## 7. Phase E:Reasonix / manifest drift guard
|
||||
|
||||
目标:在完整 7-47 capability registry 实施前,先降低 Reasonix wrapper 与 Rust manifest 的漂移风险。
|
||||
|
||||
Checklist:
|
||||
|
||||
- [x] 增加一个轻量 selftest:Rust manifest 中 `mnote.knowledge_rag.*` 三个工具必须都存在于 Reasonix wrapper 映射。
|
||||
- [x] 增加一个反向 selftest:Reasonix wrapper 暴露的 `mnote_knowledge_rag_*` 必须能映射到 Rust manifest tool name。
|
||||
- [x] 保留手写工具表作为短期现实,但在 7-47 中继续推进 manifest 动态注册。
|
||||
- [x] 若发现旧 `mnote.evidence.*` / `mnote.index.*` 函数被 grep 误判,给 manifest 源码附近加注释:dead code 仅保留历史对照,不在 manifest vector 中注册。
|
||||
|
||||
验证:
|
||||
|
||||
- [x] `MNOTE_REASONIX_ACP_SELFTEST=1 node scripts/reasonix-acp-wrapper.mjs`
|
||||
- [x] `cargo test -p mnote-web hermes_client_tools_uses_manifest_and_profile_disabled_state -- --test-threads=1`
|
||||
|
||||
实施记录:
|
||||
|
||||
- 2026-06-07:Reasonix wrapper selftest 会读取 Rust `hermes_tools/manifest.rs`,校验 `mnote.knowledge_rag.*` manifest tools 与 wrapper `MNOTE_TOOL_NAMES` / `REASONIX_TOOL_TO_MNOTE_TOOL` 双向一致。
|
||||
|
||||
## 8. Phase F:legacy OCR / Convex media visible runtime 退役跟进
|
||||
|
||||
目标:LightRAG 成为资料库主线后,继续清掉仍可能被浏览器 runtime 或 worker 误读为 active fallback 的旧 OCR / Convex Files 链路。
|
||||
|
||||
Checklist:
|
||||
|
||||
- [x] `/api/local-folder/events` 不再转发 `local_ocr.job.updated`;resource tab 不再依赖 local OCR SSE 或 `synthetic_resource_write` 刷新 filetree。
|
||||
- [x] UI preference 不再接受 `localOcr.*` 写入;历史 effective preference 强制为 `false` / retired。
|
||||
- [x] FileTree 右键入口不再保留 `local-ocr` action alias;资料索引只走 `knowledge-rag-index` 与 `/api/knowledge-rag/ingest`。
|
||||
- [x] 浏览器 runtime 不再调用 `/api/media/sign` / `/api/media/upload`;旧 Convex Files 前端链路只标记 retired guard。
|
||||
- [x] `AppState` 移除 `local_ocr_job_tx` / `local_ocr_active_jobs`,旧 local OCR helper 不再广播 runtime event。
|
||||
- [x] local search incremental refresh 遇到 OCR sidecar 时只清理旧 evidence sqlite 投影,不再重建 OCR evidence。
|
||||
- [x] `routes/local_ocr.rs` 从历史 HTTP job / MinerU runtime 实现收缩为历史 OCR sidecar 识别、frontmatter 解析和索引读取 helper;旧 ignored HTTP route tests 已移除。
|
||||
- [x] resource tab 后台任务抽屉、toolbar 与 CSS 从 `mnote-local-ocr-*` 重命名为 `mnote-knowledge-rag-*`,Knowledge RAG ingest/delete 不再挂旧 OCR DOM / function 名。
|
||||
- [x] Page AI 目标包删除空实现的 OCR sidecar context enrichment,local-first agent 只携带当前文件/selection/allowed roots,不再保留 `ocrContext` / `ocrRootRelativePath` 注入点。
|
||||
- [x] Sidebar 旧 `open-ocr-settings` / `toggle-ocr-tasks` / `data-local-ocr-*` 委托移除;历史 `.ocr/*.ocr.md` sidecar 仅以 `retired-ocr-sidecar:*` 资源身份打开,不再伪装为 active local OCR。
|
||||
|
||||
验证:
|
||||
|
||||
- [x] `cargo test -p mnote-web local_ocr -- --test-threads=1`
|
||||
- [x] `cargo test -p mnote-web local_search_ocr_sidecar_is_hidden_after_lightrag_retirement -- --test-threads=1`
|
||||
- [x] `cargo test -p mnote-web -- --test-threads=1`
|
||||
- [x] `cargo test --workspace -- --test-threads=1`
|
||||
- [x] `git diff --check`
|
||||
- [x] `codegraph sync .` / `codegraph_status`
|
||||
|
||||
## 9. 归档条件
|
||||
|
||||
- delete retry / orphan doc guard 有单测覆盖,prune 不会隐藏未确认删除的 provider doc。
|
||||
- `sourcePaths` 的 post-filter 语义在 API、skill、wrapper 和 tests 中一致。
|
||||
- locator 不再用不匹配的 first positioned block 生成非 degraded page/bbox。
|
||||
- degraded citation 的 agent / UI 文案统一。
|
||||
- `task529` / `task530` / `task531` 不依赖已漂移的固定历史 LightRAG documents 数量或 doc id。
|
||||
- 7-50 保持 `done`,本稿完成后移动到 `design/07-ai/done/`。
|
||||
@@ -3,13 +3,22 @@
|
||||
> 状态:process
|
||||
>
|
||||
> 目标:把当前分裂的 MNote builtin skill、mnote tool manifest、Hermes plugin、Reasonix wrapper 和 Page AI UI 开关收口为同一个“AI 能力”模型。对用户来说 skill / plugin / tool 都是“授予 AI 的能力”,UI 不应暴露实现层分类;实现层再把一个能力映射到说明书、工具、runtime adapter 和权限策略。本轮只整理 MNote 公共能力;Reasonix / Hermes 自带的 skills/plugins 维持现状,不纳入统一注册表迁移范围。
|
||||
>
|
||||
> 2026-06-07 口径更新:7-50 后资料库问答主线已切到 LightRAG,第一批能力包试点从旧 `mnote-local-index` 改为 `mnote-knowledge-rag`。`mnote-document-evidence` / `mnote-local-index` 只作为兼容 alias 映射到 `mnote-knowledge-rag`,不再恢复 `mnote.evidence.*` / `mnote.index.*` 作为 active tool。
|
||||
|
||||
## 当前实施状态
|
||||
|
||||
- Phase A 已落地:`rust/crates/mnote-web/src/hermes_tools/skill.rs` 已有 `MnoteCapabilityPack` / `CAPABILITY_PACKS`,`manifest.rs` 已输出 `capabilities[]` 并给 tools 标注 `capabilityId` / `capabilityIds`。
|
||||
- Phase B 已落地:`/api/hermes/client/capabilities` 已存在,Page AI `runtime=mnote` 技能目录优先请求 capabilities,能力 payload 内含 tools、readOnly、contextRefs、enabled/status。
|
||||
- Phase C 已落地:`/api/hermes/client/capabilities/toggle` 会同步 capability skill preference 和 profile tool disabled policy;直接调用被关闭 tool 会走 `mnote_tool_disabled` 硬拒绝。
|
||||
- Phase D 已完成 Reasonix 侧最小收口:`scripts/reasonix-acp-wrapper.mjs` 启动时优先读取 `/api/hermes/tools/mnote/manifest` 动态注册 MNote tool specs,mnote-web 不可用时才回落到静态 fallback;Hermes Python plugin 生成仍作为后续独立收口。
|
||||
|
||||
## 0. 用户口径
|
||||
|
||||
用户不需要理解 skill、plugin、tool 的区别。Page AI 设置中统一展示为“AI 能力”:
|
||||
|
||||
- `当前页读取`
|
||||
- `本地索引与证据检索`
|
||||
- `资料库问答`
|
||||
- `本地文件编辑`
|
||||
- `思维导图`
|
||||
- `ONLYOFFICE 实时编辑`
|
||||
@@ -35,7 +44,7 @@
|
||||
现有内置 skill:
|
||||
|
||||
- `mnote-current-page`
|
||||
- `mnote-local-index`
|
||||
- `mnote-knowledge-rag`
|
||||
- `mnote-local-file`
|
||||
- `mnote-onlyoffice-live`
|
||||
- `mnote-mindmap`
|
||||
@@ -46,7 +55,7 @@
|
||||
- skill 是 Rust 静态注册,正文来自 `skills/*/SKILL.md`。
|
||||
- `/api/hermes/client/skills?runtime=mnote&agentId=...` 通过 `mnote_builtin_skills_payload()` 输出到 UI。
|
||||
- 每个 skill 现在已经带 `toolNames` 和 `requiresContextRefs`,但这些只是弱引用,不是一个正式 capability/plugin 合同。
|
||||
- `mnote.skill.read` 能懒加载正文;旧 `mnote-document-evidence` 已作为兼容别名映射到 `mnote-local-index`。
|
||||
- `mnote.skill.read` 能懒加载正文;旧 `mnote-document-evidence` / `mnote-local-index` 只作为兼容别名映射到 `mnote-knowledge-rag`,不恢复旧 evidence / index 工具。
|
||||
|
||||
### 1.2 MNote tools
|
||||
|
||||
@@ -55,7 +64,8 @@
|
||||
现有工具大类:
|
||||
|
||||
- skill/context:`mnote.skill.read`、`mnote.context.*`
|
||||
- evidence/index:`mnote.evidence.*`、`mnote.index.*`
|
||||
- knowledge-rag:`mnote.knowledge_rag.status`、`mnote.knowledge_rag.query`、`mnote.knowledge_rag.open_reference`
|
||||
- retired evidence/index:`mnote.evidence.*`、`mnote.index.*` 只保留历史对照,不作为 active manifest / capability 示例
|
||||
- doc/block/page/artifact:`mnote.doc.*`、`mnote.block.*`、`mnote.page.*`、`mnote.artifact.*`
|
||||
- mindmap:`mnote.mindmap.*`
|
||||
- office/onlyoffice:`mnote.office.*`、`mnote.onlyoffice.*`
|
||||
@@ -178,25 +188,22 @@ pub struct MnoteCapabilityPack {
|
||||
"title": "MNote",
|
||||
"capabilities": [
|
||||
{
|
||||
"id": "mnote-local-index",
|
||||
"title": "MNote local index",
|
||||
"description": "Search local documents with evidence locators and manage local index scopes.",
|
||||
"id": "mnote-knowledge-rag",
|
||||
"title": "资料库问答",
|
||||
"description": "Ask the LightRAG-backed knowledge library and open returned MNote source references.",
|
||||
"enabled": true,
|
||||
"toggleable": true,
|
||||
"readOnly": false,
|
||||
"skillId": "mnote-local-index",
|
||||
"skillId": "mnote-knowledge-rag",
|
||||
"toolNames": [
|
||||
"mnote.evidence.search",
|
||||
"mnote.evidence.read",
|
||||
"mnote.evidence.open",
|
||||
"mnote.index.status",
|
||||
"mnote.index.refresh",
|
||||
"mnote.index.update_settings"
|
||||
"mnote.knowledge_rag.status",
|
||||
"mnote.knowledge_rag.query",
|
||||
"mnote.knowledge_rag.open_reference"
|
||||
],
|
||||
"tools": [
|
||||
{
|
||||
"name": "mnote.index.update_settings",
|
||||
"kind": "write",
|
||||
"name": "mnote.knowledge_rag.query",
|
||||
"kind": "read",
|
||||
"status": "available",
|
||||
"enabled": true,
|
||||
"requiresWritePermission": true
|
||||
@@ -221,7 +228,7 @@ pub struct MnoteCapabilityPack {
|
||||
{
|
||||
"runtime": "mnote",
|
||||
"profile": "reasonix",
|
||||
"id": "mnote-local-index",
|
||||
"id": "mnote-knowledge-rag",
|
||||
"enabled": true
|
||||
}
|
||||
```
|
||||
@@ -240,16 +247,16 @@ pub struct MnoteCapabilityPack {
|
||||
{
|
||||
"capabilities": [
|
||||
{
|
||||
"id": "mnote-local-index",
|
||||
"skillId": "mnote-local-index",
|
||||
"toolNames": ["mnote.evidence.search", "mnote.index.status"]
|
||||
"id": "mnote-knowledge-rag",
|
||||
"skillId": "mnote-knowledge-rag",
|
||||
"toolNames": ["mnote.knowledge_rag.status", "mnote.knowledge_rag.query", "mnote.knowledge_rag.open_reference"]
|
||||
}
|
||||
],
|
||||
"tools": [
|
||||
{
|
||||
"name": "mnote.index.status",
|
||||
"capabilityId": "mnote-local-index",
|
||||
"capabilityScope": ["index.read", "evidence.read"]
|
||||
"name": "mnote.knowledge_rag.query",
|
||||
"capabilityId": "mnote-knowledge-rag",
|
||||
"capabilityScope": ["knowledge_rag.read", "evidence.read"]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -261,8 +268,8 @@ pub struct MnoteCapabilityPack {
|
||||
|
||||
在 Page AI 的 Skills 页中,用户看到的是统一“AI 能力”列表,不再分 skill / plugin / tool:
|
||||
|
||||
- 行标题:`MNote local index`
|
||||
- 副标题:`索引 / 证据检索 · 6 tools · 需要 folder`
|
||||
- 行标题:`资料库问答`
|
||||
- 副标题:`知识库 / LightRAG · 3 tools · 需要 folder`
|
||||
- 状态 chip:`只读` / `可写` / `部分工具关闭` / `只读上下文不可写`
|
||||
- 主开关:启用/关闭整个能力包
|
||||
- 展开项:列出 tools,显示 read/write、enabled、status
|
||||
@@ -281,12 +288,12 @@ Runtime 页继续保留 `mnote tools`,但作为高级调试面:
|
||||
|
||||
### 4.3 索引面板与能力包关系
|
||||
|
||||
Sidebar 的“索引设置”仍是用户直接管理索引范围的产品 UI;Page AI 的 `mnote-local-index` capability 是 agent 能力开关。
|
||||
Sidebar 的“资料库 / 知识库设置”仍是用户直接管理 LightRAG source、索引范围和服务状态的产品 UI;Page AI 的 `mnote-knowledge-rag` capability 是 agent 能力开关。
|
||||
|
||||
两者职责不同:
|
||||
|
||||
- 索引设置面板:用户手动新增/删除/刷新索引范围。
|
||||
- MNote local index capability:允许 agent 使用工具帮用户查看、新增、刷新、删除索引范围。
|
||||
- 知识库设置面板:用户手动新增/删除/刷新 source,查看 LightRAG 服务和 source registry 状态。
|
||||
- MNote knowledge-rag capability:允许 agent 使用工具查询资料库、查看状态和打开返回来源;sourcePaths 当前只过滤返回 references,不声称 provider 层预过滤 raw chunks。
|
||||
|
||||
## 5. Runtime 适配
|
||||
|
||||
@@ -302,8 +309,8 @@ Sidebar 的“索引设置”仍是用户直接管理索引范围的产品 UI;
|
||||
|
||||
- 删除 `REASONIX_TOOL_TO_MNOTE_TOOL` 手写表。
|
||||
- 工具名转换统一由函数生成:
|
||||
- `mnote.index.status` -> `mnote_index_status`
|
||||
- `mnote.evidence.search` -> `mnote_evidence_search`
|
||||
- `mnote.knowledge_rag.status` -> `mnote_knowledge_rag_status`
|
||||
- `mnote.knowledge_rag.open_reference` -> `mnote_knowledge_rag_open_reference`
|
||||
|
||||
### 5.2 Hermes ACP
|
||||
|
||||
@@ -332,7 +339,7 @@ Sidebar 的“索引设置”仍是用户直接管理索引范围的产品 UI;
|
||||
|
||||
验收:
|
||||
|
||||
- `mnote-local-index` 在 `/client/skills?runtime=mnote` 可见。
|
||||
- `mnote-knowledge-rag` 在 `/client/skills?runtime=mnote` 与 `/client/capabilities?runtime=mnote` 可见,`mnote-local-index` 不再作为 active capability 暴露。
|
||||
- `/api/hermes/tools/mnote/manifest` 可看到 `capabilities[]`。
|
||||
- 旧 `mnote.skill.read` 不破。
|
||||
|
||||
@@ -345,8 +352,8 @@ Sidebar 的“索引设置”仍是用户直接管理索引范围的产品 UI;
|
||||
|
||||
验收:
|
||||
|
||||
- Page AI Skills 页中 `MNote local index` 像公共 skill 一样可见。
|
||||
- 展开能看到 `mnote.evidence.*` 和 `mnote.index.*`。
|
||||
- Page AI Skills / 能力页中 `资料库问答` 像公共 skill 一样可见。
|
||||
- 展开能看到 `mnote.knowledge_rag.*`,看不到 `mnote.evidence.*` / `mnote.index.*` active tools。
|
||||
- 开关 capability 后,下一次 run 的 `skillPreferences.mnote` 同步变化。
|
||||
|
||||
### Phase C:能力包开关驱动工具开关
|
||||
@@ -357,8 +364,8 @@ Sidebar 的“索引设置”仍是用户直接管理索引范围的产品 UI;
|
||||
|
||||
验收:
|
||||
|
||||
- 关闭 `mnote-local-index` 后 agent 不再看到该 skill 摘要。
|
||||
- 关闭后直接调用 `mnote.index.status` 返回 `mnote_tool_disabled` 或 capability disabled。
|
||||
- 关闭 `mnote-knowledge-rag` 后 agent 不再看到该 skill 摘要。
|
||||
- 关闭后直接调用 `mnote.knowledge_rag.query` 返回 `mnote_tool_disabled` 或 capability disabled。
|
||||
- 再打开后恢复。
|
||||
|
||||
### Phase D:生成 Reasonix/Hermes adapters
|
||||
@@ -373,22 +380,19 @@ Sidebar 的“索引设置”仍是用户直接管理索引范围的产品 UI;
|
||||
- `node scripts/reasonix-acp-wrapper.mjs` selftest 覆盖 manifest 动态注册。
|
||||
- `hermes plugins list` / Hermes tool list 显示与 Rust manifest 一致。
|
||||
|
||||
## 7. 对 mnote-local-index 的落地形态
|
||||
## 7. 对 mnote-knowledge-rag 的落地形态
|
||||
|
||||
`mnote-local-index` 是第一批公共能力包试点:
|
||||
`mnote-knowledge-rag` 是第一批公共能力包试点:
|
||||
|
||||
- skill:`skills/mnote-local-index/SKILL.md`
|
||||
- skill:`skills/mnote-knowledge-rag/SKILL.md`
|
||||
- tools:
|
||||
- `mnote.evidence.search`
|
||||
- `mnote.evidence.read`
|
||||
- `mnote.evidence.open`
|
||||
- `mnote.index.status`
|
||||
- `mnote.index.refresh`
|
||||
- `mnote.index.update_settings`
|
||||
- `mnote.knowledge_rag.status`
|
||||
- `mnote.knowledge_rag.query`
|
||||
- `mnote.knowledge_rag.open_reference`
|
||||
- requiresContextRefs:`folder`
|
||||
- readOnly:`false`
|
||||
- write guard:只 `mnote.index.update_settings` 写设置;必须 `dryRun/idempotencyKey`;共享只读禁止写。
|
||||
- UI 文案:`索引 / 证据检索 · 可管理索引范围`
|
||||
- readOnly:`true`
|
||||
- write guard:本能力包不写用户 source;source 管理 UI / API 另归知识库设置面,不通过 agent capability 暴露写入。
|
||||
- UI 文案:`知识库 / LightRAG · 可回跳来源`
|
||||
|
||||
## 8. 非目标
|
||||
|
||||
|
||||
+5
-2
@@ -1,8 +1,11 @@
|
||||
# 7-46 [process] Document Evidence Retrieval Kernel v1
|
||||
# 7-46 [reference] Document Evidence Retrieval Kernel v1
|
||||
|
||||
> 创建时间:2026-06-03
|
||||
>
|
||||
> 当前状态:`PROCESS`
|
||||
> 当前状态:`REFERENCE`
|
||||
>
|
||||
> 2026-06-07 状态治理:7-50 LightRAG 已覆盖默认资料库问答主线,`mnote.evidence.*` / LiteParse / evidence.sqlite 不再作为 active agent capability 或资料库 fallback。本文件只保留为历史迁移、locator 合同和旧实现审计参考,不再从 checklist 中派发新任务。
|
||||
> 文内未勾选项均为历史状态,不作为当前 `process` 任务。
|
||||
>
|
||||
> Owner:07-ai / 03-rust-web / 01-tree-first-graph-kernel
|
||||
>
|
||||
+7
-4
@@ -1,8 +1,11 @@
|
||||
# 7-48 [process] Paperless-ngx Reference: Resource Ingestion / Job Ledger / Evidence Index v1
|
||||
# 7-48 [reference] Paperless-ngx Reference: Resource Ingestion / Job Ledger / Evidence Index v1
|
||||
|
||||
> 创建时间:2026-06-05
|
||||
>
|
||||
> 当前状态:`PROCESS`
|
||||
> 当前状态:`REFERENCE`
|
||||
>
|
||||
> 2026-06-07 状态治理:本文只作为 Paperless-ngx 对 LightRAG source registry、job ledger、索引可重建性和历史 evidence.sqlite 设计的参考材料,不再作为 active evidence.sqlite / LiteParse 主线任务源。
|
||||
> 文内未勾选项均为历史候选,不作为当前 `process` 任务。
|
||||
>
|
||||
> Owner:07-ai / 03-rust-web / control-plane / 01-tree-first-graph-kernel
|
||||
>
|
||||
@@ -15,7 +18,7 @@
|
||||
> 上位依据:
|
||||
> - `/mnt/Data1T/mnote/ARCHITECTURE.md`
|
||||
> - `/mnt/Data1T/mnote/CURRENT_ARCHITECTURE.md`
|
||||
> - `/mnt/Data1T/mnote/design/07-ai/process/7-46-document-evidence-retrieval-kernel-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/07-ai/reference/7-46-document-evidence-retrieval-kernel-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/03-rust-web/done/3-25-local-folder-mineru-ocr-sidecar-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.md`
|
||||
|
||||
@@ -405,7 +408,7 @@ Owner:07-ai / 03-rust-web
|
||||
- [ ] 在 `core-protocol` 增加 `ResourceWorkJob` / `ResourceWorkJobStatus` / `ResourceWorkTriggerSource` 合同。
|
||||
- [ ] 在 job 合同中加入 `stage / stageLabel / progressCurrent / progressTotal`,作为前台任务中心稳定字段。
|
||||
- [ ] 明确 `local_ocr.job.updated` 与新 `resource_work.job.updated` 的兼容关系。
|
||||
- [ ] 在 `7-46` 里引用本设计作为 job / index lifecycle 的执行补充。
|
||||
- [x] 本设计已作为 `7-46` 历史 job / index lifecycle 参考,不再作为 active 执行补充。
|
||||
|
||||
验收:
|
||||
|
||||
+22
-15
@@ -2,7 +2,7 @@
|
||||
|
||||
> 创建时间:2026-06-06
|
||||
>
|
||||
> 状态:`process`
|
||||
> 状态:`done`
|
||||
>
|
||||
> Owner:10-review / 03-rust-web / 05-editor-mainline / 07-ai
|
||||
|
||||
@@ -30,28 +30,35 @@
|
||||
|
||||
### P1:Local-folder event bus
|
||||
|
||||
- [ ] 新建 `03-rust-web` process:浏览器端 local-folder event bus。
|
||||
- [ ] 目标是 sidebar、document session、resource tab 订阅同一 `/api/local-folder/events` 连接。
|
||||
- [ ] 验收要统计同一页面只有一个 local-folder EventSource,且后台写入仍能触发 document refresh 与 localized filetree refresh。
|
||||
- [x] 已完成并归档 `design/03-rust-web/done/3-24-local-folder-browser-event-bus-v1.md`。
|
||||
- [x] sidebar、document session、resource tab 已订阅同一 local-folder event bus。
|
||||
- [x] `task540` 已验证同一页面只有一个 local-folder EventSource,且后台写入仍能触发 document refresh 与 localized filetree refresh。
|
||||
|
||||
### P2:Page Aggregate local-first hard guard
|
||||
|
||||
- [ ] 新建或更新 `05-editor-mainline` process:local-first 文档页必须优先消费 `page_aggregate.block_document`。
|
||||
- [ ] 对 `compat.legacy_content` fallback 增加 local-first telemetry 或负向 smoke,确保它只出现在 cloud/legacy/explicit compat 场景。
|
||||
- [ ] 保存链路继续向 `EditorBlockDocument` / `tiptapDocument` 单一主 payload 收口。
|
||||
- [x] 已完成并归档 `design/05-editor-mainline/done/5-36-page-aggregate-local-first-hard-guard-v1.md`。
|
||||
- [x] 对 `compat.legacy_content` fallback 增加 local-first DOM diagnostic,`task541` 断言 local `.md` 为 `page_aggregate.block_document`。
|
||||
- [x] 保存链路未扩大 legacyBlocks 使用面,`task167` 覆盖 local-first title/body/options 写入回读。
|
||||
|
||||
### P3:7-18 agent edit clean/dirty smoke
|
||||
|
||||
- [x] 在不碰 LightRAG 的前提下,拆出 `design/07-ai/process/7-18-agent-edit-clean-dirty-smoke-checklist-v1.md`。
|
||||
- [ ] 验 clean buffer:agent 原生 patch 修改当前 `.md` 后,watcher -> BufferStore -> Page Aggregate -> ProseMirror 可见更新。
|
||||
- [ ] 验 dirty buffer:外部 agent 写入不会静默覆盖,必须出现冲突或 review 状态。
|
||||
- [ ] 验 readonly:写入型 run 在 ACP/tool 层前置拒绝,而不是只靠审计后置记录。
|
||||
- [x] 在不碰 LightRAG 的前提下,拆出并完成 `design/07-ai/done/7-18-agent-edit-clean-dirty-smoke-checklist-v1.md`。
|
||||
- [x] 验 clean buffer:agent 原生 patch 修改当前 `.md` 后,watcher -> BufferStore -> Page Aggregate -> ProseMirror 可见更新。
|
||||
- [x] 验 dirty buffer:外部 agent 写入不会静默覆盖,必须出现冲突或 review 状态。
|
||||
- [x] 验 readonly:写入型 run 在 ACP/tool 层前置拒绝,而不是只靠审计后置记录。
|
||||
- [x] 剩余归档项已在 `design/10-review/done/20-post-lightrag-runtime-hardening-checklist-v1.md` P1 完成:补真实后端 auditScope / allowed root 外写入拒绝证据后归档 7-18。
|
||||
|
||||
### P4:LightRAG diff review gate
|
||||
### P4:LightRAG post-commit audit gate
|
||||
|
||||
- [ ] 等另一个 agent 完成后,只读检查 LightRAG diff。
|
||||
- [ ] 重点核对 source registry、watcher stale/delete/reindex、query scope、`locatorDegraded`、job ledger 与 smoke 是否互相一致。
|
||||
- [ ] 若 LightRAG diff 已稳定,再决定是否新建 `7-51` 或更新现有 `7-48`。
|
||||
- [x] LightRAG 已提交并统一为 7-50 主线,旧 LiteParse / evidence / local OCR 默认路径已退役。
|
||||
- [x] 只读检查 7-50 post-commit 状态。
|
||||
- [x] 重点核对 source registry、watcher stale/delete/reindex、query scope、`locatorDegraded`、status bridge、image wrapper 与 smoke 是否互相一致。
|
||||
- [x] 发现的硬化项已拆到 `20-post-lightrag-runtime-hardening-checklist-v1.md` 并完成 `design/07-ai/done/7-51-lightrag-post-commit-hardening-v1.md`。
|
||||
|
||||
### P5:7-47 capability registry / local search / design governance follow-up
|
||||
|
||||
- [x] `20-post-lightrag-runtime-hardening-checklist-v1.md` 已继续完成 capability registry 口径重写、local search 边界和 design 状态治理。
|
||||
- [x] `7-46` / `7-48` 已降级到 `design/07-ai/reference/`,避免 worker 继续按旧 evidence / LiteParse 主线派活。
|
||||
|
||||
## 4. 非目标
|
||||
|
||||
@@ -0,0 +1,335 @@
|
||||
# 20 Post-LightRAG / Agent Edit / Runtime hardening checklist v1
|
||||
|
||||
> 创建时间:2026-06-07
|
||||
>
|
||||
> 状态:`done`
|
||||
>
|
||||
> Owner:10-review / 07-ai / 03-rust-web / 05-editor-mainline
|
||||
>
|
||||
> 上位依据:
|
||||
> - `design/07-ai/done/7-50-lightrag-knowledge-rag-provider-v1.md`
|
||||
> - `design/07-ai/done/7-51-lightrag-post-commit-hardening-v1.md`
|
||||
> - `design/07-ai/done/7-18-agent-edit-clean-dirty-smoke-checklist-v1.md`
|
||||
> - `design/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.md`
|
||||
> - `design/07-ai/process/7-47-mnote-public-capability-plugin-registry-v1.md`
|
||||
> - `design/10-review/done/19-non-lightrag-design-cleanup-followup-checklist-v1.md`
|
||||
>
|
||||
> 口径更新:LightRAG 7-50 已成为资料库问答主线,旧 LiteParse / evidence / local OCR 默认路径已退役。后续不再按“扩 RAG”理解,而是按“post-commit audit、边界硬化、减少 runtime 竞态和能力注册漂移”推进。
|
||||
|
||||
## 1. 当前工作树边界
|
||||
|
||||
当前执行本 checklist 前,需要先确认工作树中已有未提交改动的归属,避免覆盖他人或历史提交后的本地调整:
|
||||
|
||||
- `rust/crates/mnote-web/src/routes/search.rs`
|
||||
- `scripts/task452-local-search-index-browser-smoke.js`
|
||||
- `scripts/task531-lightrag-dashboard-ui-smoke.js`
|
||||
|
||||
本 checklist 默认不修改上述文件,除非本轮任务明确转入 local search / dashboard smoke 收口。
|
||||
|
||||
## 2. 执行原则
|
||||
|
||||
- 不回滚 7-50 的主线口径:资料库问答、PDF / Office / 图片 OCR、跨资料 citation 默认走 LightRAG。
|
||||
- 不恢复 `mnote.evidence.*`、`mnote.index.*`、旧 local OCR API 或 LiteParse provider 作为 agent fallback。
|
||||
- 不把 LightRAG storage、input wrapper、sidecar、chunk、vector、graph 当成用户正文真相;MNote local-folder source 仍是真相。
|
||||
- 不在普通页面搜索、文件树、编辑器打开路径中引入对 LightRAG 可用性的硬依赖。
|
||||
- 发现需要更细粒度实施时,先在对应 `design/*/process/` 下拆子 checklist,再实施代码。
|
||||
- 可以使用 subagent,但 subagent 只能做受控叶子任务:限定读写范围、验证命令、交付文件、禁止再派生 runner / subagent / worktree;主控必须复核 diff 和验证结果。
|
||||
|
||||
## 3. P0:LightRAG 7-50 post-commit audit
|
||||
|
||||
目标:确认 7-50 作为 `done` 主线是稳定的,找出需要补的硬边界,不重复建设第二套 RAG。
|
||||
|
||||
Checklist:
|
||||
|
||||
- [x] 只读 review 7-50 相关改动面:
|
||||
- `rust/crates/mnote-web/src/routes/knowledge_rag.rs`
|
||||
- `rust/crates/mnote-web/src/hermes_tools/knowledge_rag.rs`
|
||||
- `rust/crates/mnote-web/src/hermes_tools/manifest.rs`
|
||||
- `rust/crates/mnote-web/src/hermes_tools/skill.rs`
|
||||
- `scripts/reasonix-acp-wrapper.mjs`
|
||||
- `skills/mnote-knowledge-rag/SKILL.md`
|
||||
- 资料库设置 UI、FileTree 状态灯、Page AI final answer smoke。
|
||||
- [x] 核对 source truth:registry 必须以 MNote source path 为真相;symlink / input wrapper / parsed cache 只作为派生物。
|
||||
- [x] 核对 delete / prune 语义:`delete-source`、watcher stale sync、prune registry 不得删除用户原始 source。
|
||||
- [x] 核对 stale / deleted source:source 删除、hash 变化、rename / move 后,旧 LightRAG reference 不得继续作为有效 citation 暴露。
|
||||
- [x] 核对 status bridge:ingest / reindex 后的状态同步必须是有界 backoff;不得形成长期无界前台 polling。
|
||||
- [x] 核对 image wrapper:图片 source 生成 Markdown wrapper 后,registry 和 citation 仍映射回原始图片 source,而不是把 wrapper 当用户资料真相。
|
||||
- [x] 核对 query scope:`sourcePaths` 当前是否只是 query 后过滤 MNote mapped references;若 provider 层未能预过滤,UI / agent 文档必须明确这是“provider 检索后 MNote scope 过滤”。
|
||||
- [x] 核对 locator 降级:无 page / bbox / sidecar 命中时必须返回并展示 `locatorDegraded=true`,不得伪造页码、bbox 或 block id。
|
||||
- [x] 核对 LightRAG dashboard:MNote 只打开或嵌入 dashboard,不接管 LightRAG 内部图谱 / 文档任务真相。
|
||||
|
||||
审计结论:
|
||||
|
||||
- source truth、image wrapper、delete 不删用户 source、status bridge 有界 backoff、旧 evidence/index tool retired 口径均有代码和测试证据。
|
||||
- 发现的缺口已拆到并完成 `design/07-ai/done/7-51-lightrag-post-commit-hardening-v1.md`:
|
||||
- watcher stale sync 删除失败时可能丢失 `lightRagDocId`,后续难以重试 provider orphan doc 删除;Phase A 已补保留 doc id、retry 状态、delete confirmed 后清 doc id 和 unmapped reference 过滤。
|
||||
- `sourcePaths` 是 provider 检索后过滤 mapped references,HTTP API 仍返回未过滤 `raw`;已显式返回 `sourceScopeMode=post_filter_mapped_references` 与 `rawScopeFiltered=false`。
|
||||
- sidecar locator 的 `first_positioned_block` fallback 可能在 quote 不匹配时生成错误 page/bbox;已移除 fallback,未匹配时降级到 resourceTab citation。
|
||||
- degraded citation 的 skill / wrapper / UI 文案已统一,并由 Page AI final answer smoke 覆盖。
|
||||
- Reasonix wrapper 仍是手写工具表;已补短期 drift guard,长期按 7-47 动态注册。
|
||||
|
||||
验证:
|
||||
|
||||
- [x] `cargo test -p mnote-web knowledge_rag -- --nocapture`
|
||||
- [x] `MNOTE_REASONIX_ACP_SELFTEST=1 node scripts/reasonix-acp-wrapper.mjs`
|
||||
- [x] `node --check scripts/task529-knowledge-rag-citation-resource-tab-smoke.js`
|
||||
- [x] `node --check scripts/task530-knowledge-rag-page-ai-final-answer-smoke.js`
|
||||
- [x] `node --check scripts/task531-lightrag-dashboard-ui-smoke.js`
|
||||
- [x] `node --check scripts/task532-knowledge-rag-docx-ingestion-smoke.js`
|
||||
- [x] `node --check scripts/task533-knowledge-rag-source-watcher-sync-smoke.js`
|
||||
- [x] `node --check scripts/task534-knowledge-rag-source-management-scope-smoke.js`
|
||||
- [x] `node --check scripts/task538-knowledge-rag-source-scope-api-smoke.js`
|
||||
- [x] `node scripts/task529-knowledge-rag-citation-resource-tab-smoke.js`
|
||||
- [x] `node scripts/task530-knowledge-rag-page-ai-final-answer-smoke.js`
|
||||
- [x] `node scripts/task531-lightrag-dashboard-ui-smoke.js`
|
||||
- [x] `node scripts/task532-knowledge-rag-docx-ingestion-smoke.js`
|
||||
- [x] `node scripts/task533-knowledge-rag-source-watcher-sync-smoke.js`
|
||||
- [x] `MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3300 node scripts/task534-knowledge-rag-source-management-scope-smoke.js`
|
||||
- [x] `MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3300 node scripts/task538-knowledge-rag-source-scope-api-smoke.js`
|
||||
|
||||
运行态验证结果:
|
||||
|
||||
- `cargo test -p mnote-web knowledge_rag -- --nocapture` 通过 27 项。
|
||||
- Reasonix ACP selftest 通过。
|
||||
- `task529` 已改为当前可重复的 image source 降级 citation 正例;2026-06-07 在当前 3000 通过,验证 query/open_reference citationUrl 能打开 image resource tab,且不伪造 page/bbox。
|
||||
- `task531` 已改为读取当前 status documents summary,不再硬编码 `Completed (5)` / `Fail (4)` / 固定扫描 PDF doc id;2026-06-07 在当前 3000 通过,验证 Documents / Graph / Retrieval 入口。
|
||||
- `task530` 已改为当前可重复的 image source degraded citation 场景;2026-06-07 在当前 3000 通过,验证 Page AI Reasonix 最终回答可引用降级 citation,且不编造 p.N / bbox、不泄漏 raw JSON / tool 名。
|
||||
- `task538` 新增 API-only source scope smoke;2026-06-07 在 3300 新构建通过,验证 `sourceScopeMode=post_filter_mapped_references`、`rawScopeFiltered=false`、references 过滤和 `delete-source` 不删除原始 source。
|
||||
- `task534` 已修复默认过滤导致 source row 不可见的问题;2026-06-07 在 3300 最新构建通过,覆盖 UI source management、删除索引不删原始 source、删除后 scoped query 不再返回该 source。
|
||||
- `task532` 当前 3000 通过:DOCX ingestion、degraded citation、Office resource tab 打开均验证成功。
|
||||
- `task533` 当前 3000 通过:watcher Remove(File) batch、registry stale/delete 标记、query 不继续暴露 deleted source 已验证。
|
||||
- `7-51` Phase A/B/C/D/E 已完成主要代码硬化和单测/selftest;已移动到 `design/07-ai/done/`。
|
||||
|
||||
产出:
|
||||
|
||||
- [x] 若只发现小问题,直接在本 checklist 记录 audit 结果和 follow-up。
|
||||
- [x] 若发现需要代码硬化,新建 `design/07-ai/process/7-51-lightrag-post-commit-hardening-v1.md`,拆 Phase A/B/C 后再实施;完成后已归档到 `design/07-ai/done/7-51-lightrag-post-commit-hardening-v1.md`。
|
||||
|
||||
## 4. P1:7-18 agent file edit 归档收尾
|
||||
|
||||
目标:把 local-first 普通 Markdown agent 原生文件编辑从 `process` 收到可归档状态。
|
||||
|
||||
Checklist:
|
||||
|
||||
- [x] 补 clean smoke 的真实后端 audit 证据:不要只依赖 mocked SSE receipt;要证明后端 `local_agent_audit` 的 `auditScope` 使用 `allowed_files`。
|
||||
- [x] 在 `task535` 或新 `task539` 中断言 `auditScope.fileCount=1` 或等价目标文件范围证据。
|
||||
- [x] smoke 继续断言不调用 `/api/documents/save`、`mnote.doc.markdown_edit`、`mnote.page.save`。
|
||||
- [x] 补 allowed roots 外写入拒绝验证:run payload 或 agent result 涉及 root 外路径时,后端 / wrapper / 审计层必须拒绝,不得返回成功 receipt。
|
||||
- [x] 补发送后 frozen target 摘要:消息或 run 记录里能看到当次冻结 target;用户切换 tab 不影响已启动 run 的目标可解释性。
|
||||
- [x] 多 tab / 跨 workspace / dirty write 确认先拆设计,不强行塞进当前 7-18 归档。
|
||||
- [x] 更新 `design/07-ai/process/7-18-agent-edit-clean-dirty-smoke-checklist-v1.md` 状态。
|
||||
- [x] 满足归档条件后移动到 `design/07-ai/done/`。
|
||||
|
||||
验证:
|
||||
|
||||
- [x] `cargo test -p mnote-web local_agent_audit -- --test-threads=1`
|
||||
- [x] `node scripts/task535-page-ai-local-agent-clean-edit-smoke.js`
|
||||
- [x] `node scripts/task536-page-ai-local-agent-dirty-guard-smoke.js`
|
||||
- [x] `node scripts/task537-page-ai-local-agent-readonly-write-guard-smoke.js`
|
||||
- [x] `node scripts/task539-local-agent-audit-scope-contract.js`
|
||||
- [x] 新增 allowed-root 外写入 smoke 或 targeted test。
|
||||
|
||||
运行态验证结果:
|
||||
|
||||
- `task535` 当前 3000 通过:clean buffer 下 agent 原生文件 patch 后,receipt refresh 触发当前文档和 filetree 刷新,tiptap 可见更新,且未调用旧保存/写入工具。
|
||||
- `task536` 当前 3000 通过:dirty buffer 在 `/runs` 前阻塞,磁盘未变,编辑器 dirty 文本仍可见。
|
||||
- `task537` 当前 3000 通过:readonly 写入在 `/runs` 前阻塞,磁盘未变。
|
||||
- `task539` 当前 3000 通过:复跑 `task535`,断言 frozen target / allowedFiles;同时跑 `cargo test -p mnote-web local_agent_audit -- --test-threads=1`,证明后端 auditScope 使用 `allowed_files` / `fileCount=1`,并覆盖 client 注入 root 外 `allowedRoots` 会被 SQLite grant 改写。
|
||||
|
||||
## 5. P2:Local-folder browser event bus
|
||||
|
||||
目标:减少 sidebar、document session、resource tab、Page AI receipt 对 local-folder watcher / realtime / refresh 的重复连接和竞态。
|
||||
|
||||
先拆设计:
|
||||
|
||||
- [x] 新建并完成归档 `design/03-rust-web/done/3-24-local-folder-browser-event-bus-v1.md`。
|
||||
- [x] 盘点现有入口:
|
||||
- `rust/crates/mnote-web/browser/tree-live-controller.js`
|
||||
- `rust/crates/mnote-web/browser/sidebar-tree-live-apply-runtime.js`
|
||||
- `rust/crates/mnote-web/browser/document-session-runtime.js`
|
||||
- `rust/crates/mnote-web/browser/document-resource-tab-runtime.js`
|
||||
- `rust/crates/mnote-web/browser/sidebar-page-ai-runtime.js`
|
||||
- [x] 明确 event bus 的输入源:`/api/realtime/ws` 主链、`/api/tree/events` SSE fallback、Page AI receipt synthesized batch。
|
||||
- [x] 明确 event bus 的输出事件:
|
||||
- `watch_batch`
|
||||
- `document_changed`
|
||||
- `resource_changed`
|
||||
- `filetree_parent_changed`
|
||||
- `knowledge_rag_source_updated`
|
||||
- `resync_required`
|
||||
- [x] 明确订阅方职责:sidebar 只刷新 projection / filetree parent;document session 只刷新当前文档;resource tab 只刷新当前资源;Page AI 只派发 receipt refresh。
|
||||
|
||||
设计产出:
|
||||
|
||||
- `design/03-rust-web/done/3-24-local-folder-browser-event-bus-v1.md` 已记录当前重复连接来源、bus 输入/输出事件、订阅方职责、分 Phase 实施和 smoke 验收。
|
||||
|
||||
实施 Checklist:
|
||||
|
||||
- [x] 新增浏览器 singleton:同一 `workspaceId/rootUri` 只允许一个 realtime 连接。
|
||||
- Phase A 已新增 `local-folder-event-bus-runtime.js`,并让 `tree-live-controller.js` 的 local-folder 分支优先通过 `window.__mnoteLocalFolderEventBus.startLocalFolderWatcher(...)` 创建 watcher;`document-session-runtime.js` / `document-resource-tab-runtime.js` 仍待 Phase C 切换后才能勾选总体验收。
|
||||
- Phase C-1 已让 document session 与 passive resource tab 在 bus 可用时复用 root 级 watcher;`task540` 已验证 sidebar/tree live + document session 同页只创建 1 个 `/api/local-folder/events` EventSource。resource tab + Page AI 全组合仍待 smoke 扩展后勾选总项。
|
||||
- 扩展 `task540` 覆盖 resource tab 后发现 tree live / resource tab 的 workspaceId 解析可能不一致,已把 bus 连接 key 收口为页面内 `rootUri`,避免同一 root 重复建 watcher。
|
||||
- `task540` 当前在 3300 通过,已覆盖 document page + passive resource tab + `synthetic_page_ai_receipt` 同页只创建 1 个 `/api/local-folder/events`;真实 Page AI 面板点击到 receipt 的完整 UI 链路仍待扩展。
|
||||
- [x] 保留 WS 主链和 SSE fallback,但连接创建由 event bus 统一管理。
|
||||
- 非 local-folder tree live 仍保留 `tree-live-ws` / `tree-live-sse`;local-folder watcher 正常路径由 event bus 统一管理,bus 不可用时保留旧 EventSource fallback。
|
||||
- [x] `refreshLocalFolderSidebarSnapshot` 增加 orchestrator:同一 tick 合并请求、记录 reason、避免重复 sidebar projection 和 filetree parent refresh。
|
||||
- [x] sidebar live apply 改为订阅 event bus,不直接拥有全部连接与刷新策略。
|
||||
- [x] document session 改为订阅当前文档变更事件,不直接假设所有 watch batch 都要刷新。
|
||||
- [x] resource tab 改为订阅资源路径变更事件,不与 document session 重复处理。
|
||||
- [x] Page AI receipt 转为 event bus synthetic event,避免 receipt + watcher echo 双刷新。
|
||||
- 当前仍保留 bus 不可用时的旧 `tree:local-folder-watch-batch` fallback。
|
||||
|
||||
验证:
|
||||
|
||||
- [x] 新增 smoke:同一页面只存在一个 WS 或 EventSource local-folder realtime 连接。
|
||||
- `scripts/task540-local-folder-event-bus-single-connection-smoke.js` 已新增并在 3300 通过;当前覆盖 sidebar/tree live + document session + passive resource tab + Page AI synthetic receipt,尚未覆盖真实 Page AI 面板点击完整链路。
|
||||
- [x] 外部修改当前 `.md` 后,tiptap 可见刷新。
|
||||
- [x] 外部新增 / 删除文件后,filetree 只做局部 parent refresh。
|
||||
- [x] Page AI agent file edit receipt 后,不重复请求 sidebar projection。
|
||||
- [x] 复跑 tree realtime 基线:`task446`、`task447`、`task448` 或相邻 smoke。
|
||||
- `task446` / `task447` / `task448` 当前仍请求无 workspace 的 `/api/tree/commands` cloud/Convex 旧入口,结果为 `convex_retired`,不作为 local-folder event bus 证据。
|
||||
- 相邻 local-folder runtime smoke 已通过:`task435`、`task436`、`task535`、`task540`。
|
||||
|
||||
运行态验证结果:
|
||||
|
||||
- `task540` 在 3300 最新 mnote-web 通过:document page + passive resource tab + `synthetic_page_ai_receipt` 同页只创建 1 个 `/api/local-folder/events`;连续两个同 tick receipt 只触发 1 次 filetree parent projection,sidebar projection 为 0。
|
||||
- `task535` 在 3300 最新 mnote-web 通过:真实 Page AI clean agent receipt 后当前文档和 filetree 均刷新,且未调用 `/api/documents/save`、`mnote.doc.markdown_edit`、`mnote.page.save`。
|
||||
- `task436` 在 3300 最新 mnote-web 通过:当前打开 local `.md` 外部修改后 tiptap 可见刷新,dirty 文档进入冲突保护。
|
||||
- `task435` 在 3300 最新 mnote-web 通过:外部创建/重命名/删除 Markdown 与非 Markdown 资源后 page tree / filetree 原地更新且无 reload。
|
||||
|
||||
## 6. P3:Page Aggregate local-first hard guard
|
||||
|
||||
目标:防止 local-first 文档页回落到 legacy block / compat content 影子路径。
|
||||
|
||||
Checklist:
|
||||
|
||||
- [x] 新建或更新 `design/05-editor-mainline/process/*page-aggregate-local-first-hard-guard*.md`;完成后已归档为 `design/05-editor-mainline/done/5-36-page-aggregate-local-first-hard-guard-v1.md`。
|
||||
- [x] 复核 `document-tiptap-conversion-runtime.js` 的 source 判定:local-first 正常路径必须优先 `page_aggregate.block_document`。
|
||||
- [x] 对 `compat.legacy_content` fallback 增加 telemetry 或 DOM diagnostic,便于 smoke 断言。
|
||||
- [x] local-first `.md` 文档页 smoke 断言不得出现 `compat.legacy_content`。
|
||||
- [x] cloud / legacy / explicit compat 场景继续允许 fallback,并保留独立 contract test。
|
||||
- [x] 保存链路继续向 `EditorBlockDocument` / `tiptapDocument` 单一主 payload 收口,不扩大 legacyBlocks 使用面。
|
||||
|
||||
验证:
|
||||
|
||||
- [x] `node scripts/task522-page-aggregate-compat-fallback-contract.js`
|
||||
- [x] `node scripts/task167-local-markdown-title-body-options-no-convex-smoke.js`
|
||||
- [x] 新增并通过 `node scripts/task541-page-aggregate-local-first-hard-guard-smoke.js`
|
||||
- [x] 涉及保存链路时补跑 Page Aggregate body / options smoke;本轮未改保存链路,已用 `task167` 覆盖 local-first title/body/options 写入与回读。
|
||||
|
||||
运行态验证结果:
|
||||
|
||||
- `task522` 通过:`blockDocument` 优先于 legacy content,explicit compat legacy-only 仍允许 `compat.legacy_content`。
|
||||
- `task167` 通过:local-first Page Aggregate 保持 `projectionSource=local_markdown.content` 且输出 `blockDocument`,标题、正文、页面设置写入后不退回 legacy。
|
||||
- `task541` 通过:真实浏览器打开 local `.md`,editor root 诊断为 `data-mnote-page-body-source=page_aggregate.block_document`、`data-mnote-page-body-local-compat-fallback=false`、`data-mnote-page-body-hard-guard=local_ok`。
|
||||
- `cargo test -p mnote-web document_editor_adapter_runtime_contains_host_contracts -- --test-threads=1` 通过,覆盖 runtime source 诊断合同。
|
||||
|
||||
## 7. P4:7-47 capability registry 口径重写与实施
|
||||
|
||||
目标:减少 Hermes manifest、Reasonix wrapper、Page AI UI、tool disabled policy 的手写漂移。
|
||||
|
||||
先修订设计:
|
||||
|
||||
- [x] 更新 `design/07-ai/process/7-47-mnote-public-capability-plugin-registry-v1.md`,把试点从 `mnote-local-index` 改为 `mnote-knowledge-rag`。
|
||||
- [x] 删除或改写 `mnote.evidence.*`、`mnote.index.*` 作为 active capability 示例的内容。
|
||||
- [x] 明确旧 alias:`mnote-document-evidence` / `mnote-local-index` 只映射到 `mnote-knowledge-rag`,不恢复旧工具。
|
||||
|
||||
Phase A:只加 registry,不改 UI 行为。
|
||||
|
||||
- [x] 新增或整理 capability pack 单一注册表。
|
||||
- [x] Rust manifest tools 自动带 `capabilityId`。
|
||||
- [x] `/api/hermes/tools/mnote/manifest` 输出 `capabilities[]`。
|
||||
- [x] 旧 `/client/skills`、`/client/tools` 响应兼容。
|
||||
|
||||
Phase B:UI 消费 capability pack。
|
||||
|
||||
- [x] `/api/hermes/client/capabilities` 成为 Page AI “能力”页数据源。
|
||||
- [x] 能力行展示 tools 数、read/write、contextRefs、enabled 状态。
|
||||
- [x] Runtime 高级页 tools 按 capability 分组。
|
||||
|
||||
Phase C:能力包开关驱动工具硬策略。
|
||||
|
||||
- [x] `/api/hermes/client/capabilities/toggle` 同步 skill preference 与 profile tool disabled policy。
|
||||
- [x] `page_ai_capability_policy()` 过滤 disabled capability。
|
||||
- [x] `execute_mnote_tool_call()` 对 disabled capability 下的 tool 继续硬拒绝。
|
||||
|
||||
Phase D:减少 Reasonix / Hermes adapter 手写漂移。
|
||||
|
||||
- [x] Reasonix wrapper 启动时优先读取 Rust manifest 动态注册工具。
|
||||
- [x] 手写工具表降为 mnote-web 未启动时的 fallback。
|
||||
- [x] Hermes plugin 若仍需要本机 Python plugin,则从 Rust manifest 生成或同步;当前 repo 主链不直接写 `/home/lix/.hermes/plugins/mnote`,7-47 已记录为后续独立生成条件。
|
||||
|
||||
验证:
|
||||
|
||||
- [x] 新增 Rust tool 后,只改 manifest / capability pack,Page AI 能力页与 Reasonix 工具可见性同步变化。
|
||||
- [x] 关闭 `mnote-knowledge-rag` 后,agent 不看到该能力摘要。
|
||||
- [x] 关闭后直接调用 `mnote.knowledge_rag.query` 返回 disabled / capability disabled。
|
||||
- [x] `MNOTE_REASONIX_ACP_SELFTEST=1 node scripts/reasonix-acp-wrapper.mjs` 通过。
|
||||
|
||||
运行态验证结果:
|
||||
|
||||
- `cargo test -p mnote-web page_ai_capabilities_expose_knowledge_rag_and_toggle_tools -- --test-threads=1` 通过:能力页不暴露 `mnote-local-index`,暴露 `mnote-knowledge-rag`;toggle 后 `mnote.knowledge_rag.query` 在 tools 响应中为 disabled。
|
||||
- `cargo test -p mnote-web hermes_tools_manifest_exposes_mnote_capability_packs -- --test-threads=1` 通过:manifest 输出 `capabilities[]`,knowledge-rag tools 带 `capabilityIds`,旧 `mnote.index.status` 不注册。
|
||||
- `MNOTE_REASONIX_ACP_SELFTEST=1 node scripts/reasonix-acp-wrapper.mjs` 通过。
|
||||
- `timeout 3s env MNOTE_REASONIX_ACP_DEBUG=1 MNOTE_WEB_URL=http://127.0.0.1:3000 node scripts/reasonix-acp-wrapper.mjs </dev/null` 启动探针显示 `registered 7 mnote tools from runtime_manifest`。
|
||||
|
||||
## 8. P5:Local search residual boundary
|
||||
|
||||
目标:LightRAG 退役旧 evidence 后,保留 MNote 普通搜索,但不让它重新变成资料库问答或 OCR fallback。
|
||||
|
||||
Checklist:
|
||||
|
||||
- [x] 先审当前未提交的 `search.rs` / `task452` 改动归属:`search.rs` 原有 diff 主要是格式化;`task452` 原有 diff 是本地索引 settings API / backlink / tag API smoke 扩展,本轮继续按 P5 收口。
|
||||
- [x] 明确 `/api/search/documents` 只服务 Markdown 页面、资源标题、tag、backlink、普通 local search。
|
||||
- [x] 明确 `/api/search/documents` 不读旧 OCR sidecar,也不调用 LiteParse / evidence.sqlite 作为资料库问答 fallback。
|
||||
- [x] `task452` 继续验证本地搜索 settings API / tag / backlink API,但不恢复旧 local-index UI 入口,也不暗示它是资料库问答入口。
|
||||
- [x] 更新 `scripts/TESTING_REFERENCE.md` 中 local search 与 LightRAG 的边界。
|
||||
|
||||
验证:
|
||||
|
||||
- [x] `MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3300 node scripts/task452-local-search-index-browser-smoke.js`
|
||||
- [x] `cargo test -p mnote-web search_documents_local_folder -- --test-threads=1`
|
||||
- [x] `cargo test -p mnote-web local_search_ocr_sidecar_is_hidden_after_lightrag_retirement -- --test-threads=1`
|
||||
|
||||
运行态验证结果:
|
||||
|
||||
- `/api/search/documents` local-folder 响应 meta 新增 boundary:`knowledgeRag=false`、`evidenceSqliteFallback=false`、`liteParseFallback=false`、`ocrSidecarFallback=false`,并返回空 `evidence` 数组。
|
||||
- 新增/更新 targeted test 证明:普通本地搜索不再把 stale `evidence.sqlite` 命中提升为搜索结果,也不把旧 OCR sidecar 当搜索结果。
|
||||
- `task452` 在 3300 最新构建通过:搜索、settings API、backlinks/tags API 仍可用;旧 `mnote-local-index-settings-toggle` 不复活,页面保留 `mnote-knowledge-rag-settings-toggle` 作为资料库入口。
|
||||
- 宽泛 `cargo test -p mnote-web search -- --test-threads=1` 未作为 P5 通过证据:其中仍包含退役 evidence / LiteParse 旧测试和当前 local-index settings 历史失败,后续 P6 设计治理会处理旧 process / retired 测试口径。
|
||||
|
||||
## 9. P6:Design 状态治理
|
||||
|
||||
目标:减少后续 worker 从旧 process / old process 中误派活。
|
||||
|
||||
Checklist:
|
||||
|
||||
- [x] 更新并归档 `design/10-review/done/19-non-lightrag-design-cleanup-followup-checklist-v1.md`:P1/P2/P3/P4/P5 均已回填完成证据。
|
||||
- [x] 处理 `design/07-ai/process/7-46-document-evidence-retrieval-kernel-v1.md`:因 7-50 已覆盖默认资料库主线,已移到 `design/07-ai/reference/7-46-document-evidence-retrieval-kernel-v1.md` 并标注仅作历史 / migration 说明。
|
||||
- [x] 处理 `design/07-ai/process/7-48-paperless-ngx-reference-resource-ingestion-job-index-v1.md`:已移到 `design/07-ai/reference/7-48-paperless-ngx-reference-resource-ingestion-job-index-v1.md` 并标注仅作为 LightRAG / job ledger 参考,不再作为 active evidence.sqlite 主线。
|
||||
- [x] 在 `design/old/README.md` 下增加说明:old 下的 `process` 不作为 active 任务源,除非用户显式要求历史审计。
|
||||
- [x] 每次新建 checklist 必须写明 owner、非目标、验收命令和归档条件;本轮新增 `3-24` / `5-36` / `7-51` / `20` 均按该格式回填。
|
||||
|
||||
运行态验证结果:
|
||||
|
||||
- `find design/07-ai/process` 当前不再包含 `7-46` / `7-48`。
|
||||
- `design/old/README.md` 已明确 old/process 非 active 任务源。
|
||||
- `design/10-review/process/19...` 已移动到 `design/10-review/done/19...`。
|
||||
|
||||
## 10. 推荐执行顺序
|
||||
|
||||
1. P0:LightRAG 7-50 post-commit audit。
|
||||
2. P1:7-18 agent file edit 归档收尾。
|
||||
3. P2:Local-folder browser event bus。
|
||||
4. P4:7-47 capability registry 口径重写与实施。
|
||||
5. P3:Page Aggregate local-first hard guard。
|
||||
6. P5 / P6:按当前脏改和设计误读风险穿插推进。
|
||||
|
||||
## 11. 总体验收
|
||||
|
||||
- LightRAG 作为资料库问答主线稳定,source truth / stale / delete / locatorDegraded / query scope 都有证据。
|
||||
- 7-18 local-first 普通 Markdown agent 文件编辑 checklist 可归档。
|
||||
- local-folder browser runtime 不再因为多个模块各自连接和刷新导致重复请求或竞态。
|
||||
- local-first Page Aggregate 不再静默回落到 legacy content 主链。
|
||||
- MNote AI capability 注册表能减少 manifest / wrapper / UI 漂移。
|
||||
- 旧 evidence / LiteParse / local OCR 不再被 worker 误当作 active fallback。
|
||||
@@ -6,6 +6,8 @@
|
||||
> - `process/`:已废弃,但属于历史上的草稿、方案、spike、路线稿
|
||||
> - `done/`:已废弃,但属于历史上的定稿、审计、报告、边界说明
|
||||
>
|
||||
> 任务源规则:`design/old/**/process/` 不作为 active 任务源。worker 只能在用户明确要求“历史审计 / 迁移对照 / recycle 复盘”时读取这些文件;默认不得从 old/process 的 `[ ]` checklist 继续派活。
|
||||
>
|
||||
> 大类说明:
|
||||
> - `01-tree-first-graph-kernel/`:已被新清单替代的旧内核稿
|
||||
> - `03-rust-web/`:已被新清单替代的旧 Rust Web 稿
|
||||
|
||||
Reference in New Issue
Block a user