# 7-46 [reference] Document Evidence Retrieval Kernel v1 > 创建时间:2026-06-03 > > 当前状态:`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 > > 上位依据: > - `/mnt/Data1T/mnote/ARCHITECTURE.md` > - `/mnt/Data1T/mnote/CURRENT_ARCHITECTURE.md` > - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/process/1-8-mvp-post-process-execution-order-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` > - `/mnt/Data1T/mnote/design/07-ai/done/7-40-page-ai-context-envelope-and-run-receipt-v1.md` > > 参考项目:`reference-code/PageIndex`、`reference-code/BookRAG`、`reference-code/Kwipu`、`reference-code/ladybug` 曾用于架构取证;`seekdb` 本地副本已在 2026-07 清理。本文只保留架构和合同结论,不把这些项目整体引入运行时。 ## 1. 第一结论 MNote 应建设一个统一的 `Document Evidence Retrieval Kernel`,作为 Hermes / Reasonix / Page AI 搜索 PDF、Word、图片 OCR、Markdown 和附件内容的唯一证据检索入口。 核心路径: ```text 本地 Markdown / PDF / Word / 图片 / 附件 -> Parse Provider: LiteParse 或 MinerU -> Parsed Resource Artifact: parsed text + source-map -> Evidence Index: SQLite FTS + section tree + locator -> Agent Tool: mnote.evidence.search / read / open -> UI: 打开 owner 文档 / resource tab,并定位 page / bbox / section / line -> 可选 Graph Projection: LadybugDB ``` 这不是一个多项目拼装方案。PageIndex、BookRAG、Kwipu、LadybugDB、SeekDB 都只作为参考或可插拔后端,不成为默认数据真相。 第一优先级不是 graph DB,也不是替换现有 OCR,而是先把“搜索命中”升级为“可点击、可复核、可被 agent 引用的 Evidence Locator”。 ## 2. 设计原则 ### 2.1 尽量减少重复真相 每类数据只能有一个默认真相: | 数据 | 默认真相 | 说明 | | --- | --- | --- | | 原始文档 | 用户文件本身 | PDF / Word / 图片 / Markdown 原文件不被索引替代 | | OCR / parse 结果 | resource sidecar artifact | 只作为原始文档的派生证据真相,可删除重建 | | 搜索索引 | `.mnote/index/evidence.sqlite` | 只作为缓存和加速层,不作为正文真相 | | graph | SQLite edge table 或 LadybugDB projection | 只作为 evidence 的投影,不反向成为文档真相 | | agent 引用 | `EvidenceLocator` | 引用必须落回原始文档或 owner Markdown | 禁止新增第二套“文档正文真相”。不允许让 OCR Markdown、LiteParse JSON、FTS rows、graph nodes 彼此独立竞争正文口径。 ### 2.2 尽量少引入项目 默认运行时只接受两个 parser/provider: - `MinerUProvider`:复用当前已有 MinerU HTTP OCR route 和 token 管理。 - `LiteParseProvider`:作为轻量本地 PDF parser,优先用于文本型 PDF,扫描件再启 OCR。 其他项目定位: - PageIndex:借鉴 tree search,不引入运行时。 - BookRAG:借鉴 `tree + graph + evidence mapping` 架构,不引入运行时。 - Kwipu:借鉴 Markdown note graph 和 MCP query 形态,不引入运行时。 - LadybugDB:只作为后续 graph projection 后端。 - SeekDB:只作为后续 hybrid search backend 候选。 ### 2.3 优先和当前项目耦合 默认落点是 MNote 现有 Rust Web / local-first / Page AI 工具链: - 解析任务沿 `mnote-web` 的 local resource route 和当前 OCR job 模型扩展。 - 检索沿当前 `/api/search/documents`、`docs_search`、`docs_read` 兼容升级。 - agent 权限沿 `AiAccessScope`、allowed roots、targetPackage 和 run receipt。 - UI 打开沿现有 document / resource tab / local-folder route。 - 文件变化沿 watcher 刷新索引,不新增前端轮询主链。 ## 3. 当前问题 当前 local search 已能搜索 Markdown、资源标题和 OCR sidecar,`includeOcr=true` 时可以返回 owner page。但它仍然不够支撑 agent 文档问答: - OCR 命中只有 owner page 和 OCR sidecar 路径,缺 page / bbox / section 级定位。 - PDF 文本型文件即使不需要 OCR,也需要页面和 bbox source-map,否则只能纯文本命中。 - agent 需要同时拿到 quote、上下文、locator 和 open action,而不是只拿文档 id。 - graph 如果直接建在纯文本 chunk 上,会和 UI 定位脱节。 - PageIndex / BookRAG 这类 tree/graph 思路有价值,但直接引入会形成多套索引和多套真相。 ## 4. Canonical Artifact 每个被解析的资源只生成一份 canonical parsed artifact。它是原始文件的派生结果,可删除重建。 ### 4.1 文件布局 继续尊重当前 `{pageStem}.ocr/` sidecar 约定,不强行迁移已有 OCR 文件。新增 source-map 文件与当前 OCR / parse Markdown 同目录,避免分散到多个项目缓存。 示例: ```text docs/Page.md docs/Page.assets/spec.pdf docs/Page.ocr/spec.pdf.ocr.md docs/Page.ocr/spec.pdf.source-map.json ``` 文本型 PDF 使用 LiteParse 时,也写到同一 owner sidecar 目录: ```text docs/Page.ocr/spec.pdf.parse.md docs/Page.ocr/spec.pdf.source-map.json ``` 说明: - `*.ocr.md`:OCR 结果,通常来自 MinerU。 - `*.parse.md`:非 OCR parse 结果,通常来自 LiteParse。 - `*.source-map.json`:定位真相,包含 page、bbox、text item、section、char range。 - `.mnote/index/evidence.sqlite`:索引缓存,引用上述 artifact,不保存不可追溯的新正文真相。 长期可以把目录名从 `.ocr` 演进为 `.evidence`,但不作为当前必要前置;当前先减少迁移风险。 ### 4.2 `source-map.json` ```json { "schema": "mnote.resource_source_map.v1", "provider": "liteparse", "modelVersion": "2.0.5", "ownerDocumentPath": "docs/Page.md", "sourceRootRelativePath": "docs/Page.assets/spec.pdf", "sourceHash": "sha256:...", "pageCount": 12, "pages": [ { "page": 1, "width": 595, "height": 842, "textItems": [ { "id": "p1_t1", "text": "Revenue recognition", "bbox": [72, 124, 260, 140], "charRange": [0, 19] } ], "blocks": [ { "id": "p1_b1", "type": "paragraph", "text": "Revenue recognition ...", "bbox": [72, 124, 520, 180], "charRange": [0, 220] } ] } ], "sections": [ { "id": "sec_1", "title": "Revenue", "path": ["Annual Report", "Revenue"], "pageStart": 1, "pageEnd": 3, "blockIds": ["p1_b1"] } ] } ``` 约束: - `source-map.json` 是定位真相,不把同一定位信息散落到 OCR frontmatter、SQLite row 和 graph node 中。 - SQLite 和 graph 只复制必要 locator 字段作为查询加速,必须能由 source-map 重建。 - Markdown / Word 也使用同一 `EvidenceLocator` 合同,只是定位字段从 bbox 换成 heading / line / char range。 ## 5. Provider 选择 ### 5.1 LiteParseProvider 默认用途: - 文本型 PDF。 - 需要快速本地解析并保留 bbox 的 PDF。 - 不需要 OCR 的 PDF 必须走 `no-ocr` 模式。 价值: - 不是纯搜索增强,而是把文本 PDF 的“文本”升级为“可定位文本”。 - 对文本型 PDF,OCR 是浪费;LiteParse 可以保留页面坐标和阅读顺序。 - 与 MNote Rust 主线耦合度较好,适合做二次开发或 provider adapter。 不做: - 不把 LiteParse 当独立搜索引擎。 - 不让 LiteParse 直接替代 MNote index / agent tool。 - 不强行让 LiteParse 直接调用 MinerU;如需 MinerU OCR,走 MNote 自己的 `MinerUProvider`,或做明确 adapter。 ### 5.2 MinerUProvider 默认用途: - 扫描 PDF。 - 图片 OCR。 - 复杂版式 PDF。 - Office / PPT / Word 转换后需要 OCR 或结构提取的资源。 当前 MNote 已有 MinerU HTTP OCR 链路,应继续复用: - 后端读取 token,前端不接触 token。 - 结果写入 owner sidecar。 - `.mnote/ocr-index.json` 继续作为状态缓存。 - 新增 source-map 提取时,优先消费 MinerU zip 中的 JSON,而不是只取 `full.md`。 ### 5.3 Provider 选择规则 ```text if file is markdown: use MarkdownParserProvider if file is text PDF and LiteParse succeeds: use LiteParseProvider(no_ocr) if file is image/scanned PDF or LiteParse text confidence is low: use MinerUProvider if file is image: use MinerUProvider if file is Word/PPT/Excel: prefer office parser/export path, then MinerUProvider when visual locator is needed ``` 失败策略: - LiteParse 失败不自动调用外部 MinerU,除非用户或 policy 允许上传。 - MinerU 缺 token 时返回明确 `mineru_token_missing`,不伪装为成功。 - Provider output 必须写入统一 artifact 合同后才能进入 evidence index。 ## 6. Evidence Index ### 6.1 存储 新增或扩展本地索引: ```text .mnote/index/evidence.sqlite ``` SQLite 是当前最合适的默认底座: - 和 local-first 主线耦合度高。 - 无新增常驻服务。 - 可用 FTS5 做快速全文搜索。 - 可同时存 metadata、locator、section tree 和 graph edge cache。 - 后续可把同一合同投影到 LadybugDB 或 SeekDB。 当前 `.mnote/index/search-index.json` 可以继续作为兼容缓存,但不应继续承载大文档 evidence 主索引。 ### 6.2 表模型 ```sql evidence_resource( resource_id, owner_document_id, owner_document_path, source_root_relative_path, provider, source_hash, artifact_root_relative_path, source_map_root_relative_path, updated_at_ms ) evidence_block( block_id, resource_id, text, section_path_json, page_start, page_end, bbox_json, char_range_json, line_range_json, locator_json ) evidence_fts( block_id UNINDEXED, text ) evidence_section( section_id, resource_id, title, path_json, summary, page_start, page_end, parent_section_id ) evidence_edge( edge_id, from_id, to_id, edge_type, source_block_id, confidence, created_by ) ``` ### 6.3 Index 不是真相 FTS row 可以复制 `text`,但只作为查询缓存。验收规则: - 删除 `evidence.sqlite` 后,可由原始文件和 sidecar artifact 重建。 - 删除 `source-map.json` 后,对应定位能力失效,需要重新 parse。 - 删除原始文件后,sidecar 和 index 必须标记 stale,不继续当成可打开证据。 ## 7. Tree Retrieval PageIndex 的价值在于 tree search,不在于它的代码本身。 MNote 应从 source-map 和 Markdown heading 生成 `evidence_section`: ```text Document -> Resource -> Section -> Page range -> EvidenceBlock ``` Agent 检索时不是只做 BM25,也不是让 LLM 扫全文: 1. FTS 快速召回候选 evidence blocks。 2. section tree 收拢上下文和页码范围。 3. 对长文档问题,可让 LLM 在 section tree 上选择相关 section。 4. 再读取 section 内 evidence blocks。 这保留 PageIndex 的“目录树推理”优点,但不引入 PageIndex 的独立文档系统。 ## 8. Graph Retrieval Graph 是 Evidence Kernel 的投影,不是起点。 ### 8.1 Day-one graph 第一版 graph 先用 SQLite edge table 表达确定性关系: - `document_contains_resource` - `resource_contains_page` - `page_contains_block` - `section_contains_block` - `markdown_links_to` - `resource_refers_to` - `block_mentions_entity` 这些边都必须能回到 `EvidenceLocator`。 ### 8.2 LadybugDB projection 当出现以下情况,再引入 LadybugDB: - 需要 Cypher 做多跳实体关系查询。 - SQLite edge table 查询已经影响交互速度。 - 多文档 entity graph 已有稳定抽取合同。 - 需要 graph traversal 给 agent 提供明确收益。 LadybugDB 只读投影: ```text evidence.sqlite / source-map artifacts -> graph projection job -> .mnote/graph/ladybug/ ``` 禁止让 LadybugDB 反向成为 source-map、正文或 locator 真相。 ## 9. Agent Tool Contract ### 9.1 `mnote.evidence.search` 请求: ```json { "query": "合同解除条件", "scope": { "workspaceId": "local:notes", "rootUri": "file:///mnt/Data1T/notes", "targetDocumentId": null, "includeResources": true, "includeOcr": true }, "mode": "hybrid", "topK": 8 } ``` 响应: ```json { "ok": true, "results": [ { "evidenceId": "ev_spec_pdf_p3_b7", "quote": "合同任一方可在提前三十日通知后解除...", "score": 0.82, "source": { "schema": "mnote.evidence_locator.v1", "rootUri": "file:///mnt/Data1T/notes", "ownerDocumentId": "local-md:docs~2FPage.md", "ownerDocumentPath": "docs/Page.md", "resourcePath": "docs/Page.assets/spec.pdf", "resourceKind": "pdf", "page": 3, "bbox": [72, 220, 510, 268], "sectionPath": ["第二章", "解除条件"], "sourceMapPath": "docs/Page.ocr/spec.pdf.source-map.json", "openAction": { "type": "mnote.open_resource_locator", "url": "/documents/local-md:docs~2FPage.md?sourceKind=local_folder&rootUri=...&resource=docs%2FPage.assets%2Fspec.pdf&page=3&bbox=72,220,510,268" } } } ] } ``` ### 9.2 `mnote.evidence.read` 根据 locator 读取周边上下文: - 同页前后 blocks。 - 同 section 摘要。 - owner Markdown 中引用该资源的位置。 - OCR / parsed artifact 片段。 ### 9.3 `mnote.evidence.open` 只做 open action 归一化,不让 agent 拼 URL。 UI 负责: - Markdown:打开文档并跳 heading / line / block。 - PDF:打开 resource tab,滚到 page,绘制 bbox highlight。 - 图片:打开 resource tab,按 bbox highlight。 - Office:打开 resource tab,尽量定位页/段落;定位能力不足时退化到资源级打开。 ### 9.4 兼容 `docs_search` / `docs_read` `docs_search`、`docs_read` 保留,但逐步转发到 evidence tool: - 旧调用仍返回 `results`。 - 新调用额外返回 `evidence` 和 `source.locator`。 - Hermes / Reasonix prompt 中优先推荐 `mnote.evidence.search`。 ## 10. UI Contract 搜索结果和 agent answer citation 必须使用统一 locator。 展示: ```text 引用 1:Page.md / spec.pdf / 第 3 页 / 第二章 解除条件 ``` 点击行为: ```text openAction -> document shell -> resource tab -> page/bbox highlight ``` 禁止: - 只返回 OCR sidecar 文件给用户。 - 只返回内部 `local:folder:...` id。 - agent 自己拼接路径或 URL。 - graph answer 没有 evidence locator。 ## 11. 与参考项目的关系 ### 11.1 PageIndex 采用: - section tree。 - tree search。 - page / section traceability。 不采用: - 独立 PageIndex runtime。 - 让 PageIndex 拥有文档真相。 - 让 LLM 每次从大文档原文重新推理检索。 ### 11.2 BookRAG 采用: - `hierarchy + entity graph + fine-grained evidence mapping` 的整体思想。 - 不同 query 使用不同 retrieval workflow。 不采用: - Python 3.12 / conda / 研究型 pipeline 作为 MNote runtime。 - 独立 vector DB / graph DB / parser 多套真相。 ### 11.3 Kwipu 采用: - Markdown note graph 的 wikilink / frontmatter 抽取。 - MCP 工具返回带 source 的 answer 形态。 - 增量更新、模型不匹配检测和 anti-hallucination prompt 思路。 不采用: - Ollama + LlamaIndex + Python graph runtime 作为 MNote 默认后端。 - 让 Kwipu 扫描 MNote workspace 后生成另一套 graph truth。 ### 11.4 LadybugDB 采用: - 后续 property graph / Cypher / embedded graph projection。 不采用: - 第一版即替换 SQLite FTS。 - 把 graph DB 当正文、source-map 或 locator 真相。 ### 11.5 SeekDB 采用: - 观察其 hybrid vector + full-text + scalar 查询能力。 - 后续可做 `SearchBackend` provider。 不采用: - 当前默认引入。 - 用它替代 graph。 - 在 Rust local-first 核心尚未确认耦合成本前,把它放入主链。 ## 12. 权限与安全 - evidence search 必须先经过 workspace / rootUri access check。 - 外部 OCR / parse provider 上传文件前,必须遵守当前 UI 授权和 provider policy。 - MinerU token 只在后端读取,不进入前端 payload、日志和 agent context。 - Agent 只能拿到 evidence locator 和 quote,不拿 provider token、上传 URL、完整外部响应。 - `EvidenceLocator` 中的 path 必须是授权 root 下的 root-relative path 或可展示绝对路径,不返回无意义内部投影 id。 ## 13. Watcher 与刷新 索引刷新触发: - Markdown 保存。 - resource 上传 / 删除 / 移动 / 重命名。 - OCR / parse job 完成。 - source-map 写入。 - local-folder watcher 观察到相关文件变化。 刷新方式: - 单文件增量更新优先。 - 大范围 rebuild 只在索引缺失、schema 变化或 source-map 无法匹配时触发。 - 前端不新增 setInterval / polling 主链。 - job 状态继续沿 local realtime event / WS / SSE。 ## 14. 验收标准 ### 14.1 文本型 PDF - LiteParse no-OCR 解析成功。 - 生成 `*.parse.md` 和 `*.source-map.json`。 - evidence search 命中 quote。 - result 带 page + bbox + openAction。 - 点击能打开 owner document 的 resource tab,并定位到 PDF 页。 ### 14.2 图片型 PDF / 图片 - MinerUProvider 解析成功。 - 生成 `*.ocr.md` 和 `*.source-map.json`。 - `includeOcr=true` 命中 evidence。 - 缺 token 时返回 `mineru_token_missing`,不写成功 artifact。 - 点击能打开资源并定位 page / bbox;无法 bbox 时至少定位到页。 ### 14.3 Markdown / 笔记 - Markdown heading 生成 section tree。 - wikilink / resource ref 进入 deterministic edge。 - evidence search 返回 line / heading locator。 - 点击回到 Markdown 文档对应位置。 ### 14.4 Agent - Hermes / Reasonix 回答引用至少包含 quote、source title、page/section 和 openAction。 - agent 不直接读取 `.mnote/index/evidence.sqlite`。 - agent 不自行拼接 open URL。 - answer 中每个关键事实至少能回到一个 `EvidenceLocator`。 ### 14.5 Graph - SQLite edge table 能从 evidence/source-map 重建。 - graph answer 必须返回 source evidence,不允许只返回 entity relation。 - LadybugDB projection 删除后不影响 search / locator 主链。 ## 15. 实施顺序 这是同一个整体架构的落地顺序,不是多个互相竞争的方案。 1. 定义 `EvidenceLocator`、`ParsedResourceArtifact`、`SourceMap` Rust 类型和 JSON schema。 2. 扩展 MinerU sidecar:从结果 zip 中保留 JSON,写 `*.source-map.json`。 3. 接入 LiteParseProvider:文本 PDF 走 no-OCR parse,输出同一 artifact。 4. 建 `.mnote/index/evidence.sqlite` + FTS5 + section tree。 5. 新增 `mnote.evidence.search/read/open` route / tool,并让 `docs_search/docs_read` 兼容转发。 6. UI resource tab 支持 locator open/highlight。 7. Markdown wikilink / resource ref 进入 deterministic edge table。 8. 评估 LadybugDB projection,只有当 graph traversal 真正需要时再接。 ## 16. 明确非目标 - 不一次性替换当前 OCR 系统。 - 不引入 PageIndex / BookRAG / Kwipu 作为默认 runtime。 - 不默认引入 SeekDB。 - 不先上 LadybugDB 再倒推检索。 - 不让 agent 直接扫描 sidecar、SQLite 或 graph 存储。 - 不把 PDF 全量转图片作为默认方案;图片只作为 visual locator / OCR fallback。 - 不把 OCR 文本直接污染 owner Markdown 正文。 - 不让 graph 节点脱离 evidence locator。 ## 17. 需要二次开发的接口 ### 17.1 Rust trait ```rust pub trait ParseProvider { fn provider_id(&self) -> &'static str; fn can_parse(&self, input: &ParseInput) -> ParseCapability; async fn parse(&self, input: ParseInput) -> Result; } ``` Provider 不直接写索引。Provider 只返回 artifact;indexer 统一消费 artifact。 ### 17.2 Search backend trait ```rust pub trait EvidenceSearchBackend { fn refresh_resource(&self, artifact: &ParsedResourceArtifact) -> Result<()>; fn search(&self, request: EvidenceSearchRequest) -> Result; fn read(&self, locator: EvidenceLocator, context: EvidenceReadContext) -> Result; } ``` 默认实现是 SQLite FTS。SeekDB 只能作为后续实现之一。 ### 17.3 Graph projection trait ```rust pub trait EvidenceGraphProjection { fn refresh_edges(&self, edges: Vec) -> Result<()>; fn traverse(&self, request: EvidenceGraphRequest) -> Result; } ``` 默认实现是 SQLite edge table。LadybugDB 只能作为后续 projection 实现。 ## 18. 最终口径 MNote 的文档问答能力应以 Evidence 为核心,而不是以 OCR、vector、graph 或某个外部 RAG 项目为核心。 判断一个工具能否进入主链,只看三件事: 1. 是否能产出或消费 MNote 的 canonical `EvidenceLocator`。 2. 是否减少重复真相,而不是制造另一套文档库。 3. 是否和当前 Rust local-first / Page AI / watcher / resource tab 主链低耦合接入。 按这个标准,当前默认组合是: ```text LiteParseProvider + MinerUProvider -> MNote SourceMap / Evidence Artifact -> SQLite FTS + section tree -> mnote.evidence.* agent tool -> UI locator open/highlight -> optional LadybugDB graph projection ``` 这条线最贴近当前 MNote 项目,也最少引入互相冲突的外部项目真相。 ## 19. 详细 Checklist > 目标:把“能搜到”升级为“能定位、能引用、能回跳、能扩展图谱”,同时不引入重复真相。 ### 19.1 统一证据合同 - [x] 定义 `EvidenceLocator` schema。 - [x] 定义 `ParsedResourceArtifact` schema。 - [x] 定义 `SourceMap` schema。 - [x] 定义 `EvidenceSearchRequest` / `EvidenceSearchResponse`。 - [x] 定义 `EvidenceReadRequest` / `EvidenceReadResponse`。 - [x] 定义 `EvidenceEdge` schema。 - [x] 统一 JSON 字段命名,保证 LiteParse / MinerU / Markdown 共用一套定位合同。 - [x] 明确哪些字段是 canonical,哪些字段只是 cache copy。 验收: - 任一证据都能从 locator 回到 owner 文档或 resource。 - 同一个定位字段不在多个地方各自定义不同语义。 2026-06-03 首刀证据: - 已新增 `rust/crates/core-protocol/src/evidence.rs`,导出 `EvidenceLocator`、`ResourceSourceMap`、`ParsedResourceArtifact`、`EvidenceSearch*`、`EvidenceRead*`、`EvidenceEdge`。 - 已在 `core-protocol` tool registry 注册 `mnote.evidence.search`、`mnote.evidence.read`、`mnote.evidence.open` 只读工具。 - 字段口径:原始文件、owner Markdown、`*.source-map.json` 与 `EvidenceLocator` 是 canonical;`search-index.json`、未来 `evidence.sqlite` row、graph node/edge 中复制的 page/bbox/text/section 字段都只是 cache copy,必须能从 canonical artifact 重建。 - 验证:`cargo test --manifest-path rust/Cargo.toml -p core-protocol --lib`。 ### 19.2 资源解析层 - [x] 实现 `ParseProvider` trait。 - [x] 实现 `MarkdownParserProvider`。 - [x] 实现 `LiteParseProvider`。 - [x] 复用现有 `MinerUProvider` 路径并输出统一 source-map sidecar。 - [x] 文本型 PDF 默认走 `no-ocr`。 - [x] 扫描 PDF / 图片默认走 MinerU。 - [x] 解析失败时保留可诊断错误,但不污染正文真相。 - [x] 解析输出必须包含 source hash,便于 stale 检测。 验收: - 同一输入文件重复解析能稳定生成一致 locator。 - 不同 provider 输出的 artifact 能进入同一后续索引链。 2026-06-03 解析层证据: - 已新增 `rust/crates/mnote-web/src/evidence_parse.rs`,定义 `ParseProvider`、`ParseInput`、`ParseProviderOutput`、`ParseCapability`、`ParseProviderMode`、`ParseError`。 - `MarkdownParserProvider` 已能读取 Markdown,生成 `ParsedResourceArtifact`、Markdown source-map、section path、line block,并输出稳定 `fnv1a64` source hash。 - `LiteParseProvider` 已接入真实 `lit parse --format json --no-ocr` CLI adapter,读取 LiteParse JSON 后生成 `ParsedResourceArtifact`、`ResourceSourceMap`、page / bbox / section / char range 与 Markdown 输出;测试用 fake `lit` 验证命令调用和 JSON 映射,不依赖 mock provider 返回。 - 2026-06-04 复核补强:`LiteParseProvider` 已兼容 LiteParse 2.0 实际 JSON 结构 `pages[].textItems[]`,bbox 同时支持 `x/y/width/height` 和 `bbox[]` 两种口径;`liteparse_runtime_available()` 会检测 `MNOTE_LITEPARSE_BIN`、`lit`、`liteparse`,当前机器已安装 `/home/lix/.npm-global/bin/lit`。 - provider 选择已补 `select_parse_provider_id`:文本 PDF / `NoOcr` 默认走 `liteparse`;OCR policy、低 native text confidence 的扫描 PDF,以及图片资源默认走 `mineru`。 - 解析失败会返回结构化 `ParseError.code/message`,不会写入 owner Markdown 或 evidence index。 - 验证:`cargo test --manifest-path rust/Cargo.toml -p mnote-web evidence_parse -- --test-threads=1`。 ### 19.3 Source-map 落盘 - [x] 确定 sidecar 目录仍沿 `{pageStem}.ocr/` 复用。 - [x] 写入 `*.parse.md`。 - [x] 写入 `*.ocr.md`。 - [x] 写入 `*.source-map.json`。 - [x] 为 source-map 记录 page / bbox / char range。 - [x] 为 source-map 记录 section path。 - [x] 为 source-map 记录 ownerDocumentPath 和 sourceRootRelativePath。 - [x] 为 source-map 记录 provider、modelVersion、sourceHash。 - [x] 保证 source-map 可独立重建定位,不依赖 `.mnote` 索引。 验收: - 删除 `.mnote/index` 后,仍可从 sidecar 重建 evidence index。 - 删除 sidecar 后,索引必须标记 stale,而不是继续假装有效。 2026-06-03 首刀证据: - MinerU 真实 HTTP mock 路径已从结果 zip 读取 `content_list.json`,生成 `*.source-map.json`。 - Source-map 目前已记录 provider、modelVersion、ownerDocumentPath、sourceRootRelativePath、sourceHash、page、bbox、block text;section 构建仍待接入 tree/outline 层。 - Evidence search route 已能从 OCR sidecar 对应的 `*.source-map.json` 读回 page、bbox、blockId、charRange 和 sourceMapPath,证明定位字段不依赖 `.mnote` 索引缓存。 - 验证:`cargo test --manifest-path rust/Cargo.toml -p mnote-web local_ocr_jobs_route_runs_mineru_runtime_against_http_mock -- --test-threads=1`。 ### 19.4 Evidence Index - [x] 建 `.mnote/index/evidence.sqlite`。 - [x] 建 `evidence_resource` 表。 - [x] 建 `evidence_block` 表。 - [x] 建 `evidence_section` 表。 - [x] 建 `evidence_edge` 表。 - [x] 建 FTS5 索引。 - [x] 将 `search-index.json` 降级为兼容缓存,不再承载主 evidence 语义。 - [x] 索引写入必须由 artifact 驱动,而不是由 UI 拼装驱动。 - [x] 增量更新优先于全量 rebuild。 验收: - 单文件修改只更新相关 resource 和 blocks。 - 索引可由原始文件和 sidecar 全量重建。 2026-06-03 首刀证据: - `local_search_index` 刷新时会同步写 `.mnote/index/evidence.sqlite`,包含 `evidence_meta`、`evidence_resource`、`evidence_block`、`evidence_fts`、`evidence_section`、`evidence_edge`。 - 当前 evidence.sqlite 已覆盖 Markdown、resource 和 OCR sidecar 基础 blocks;`/api/evidence/search` 已切为 evidence.sqlite FTS/LIKE 优先,`search-index.json` 只作为缺少 evidence.sqlite 时的兼容 fallback。 - Evidence index 写入已拆到 artifact 链:Markdown 会构造 `ParsedResourceArtifact` 后写 resource/block;OCR/source-map 资源会由 `ParsedResourceArtifact + ResourceSourceMap` 驱动写入 resource、section、block 与 locator,不再由 UI projection 拼 evidence 语义。 - 2026-06-04 复核补强:local index 刷新已对 Markdown 引用到的 PDF / Office 资源执行 LiteParse 正文解析,写入 `{ownerStem}.ocr/{resource}.parse.md` 与 `{ownerStem}.ocr/{resource}.source-map.json`,再由 artifact 写入 `.mnote/index/evidence.sqlite`;sidecar 自身会被跳过,避免 parse 结果被当普通 Markdown 重复索引。 - `refresh_local_search_index_for_path` 已改为写兼容 `search-index.json` 后调用 `refresh_evidence_sqlite_index_for_path`,只删除并重建受影响 resource / block / edge;全量 `write_evidence_sqlite_index` 仍只用于初始/强制 rebuild。 - 验证:`cargo test --manifest-path rust/Cargo.toml -p mnote-web search_documents_local_folder_uses_authorized_root_index -- --test-threads=1`。 - 验证:`cargo test --manifest-path rust/Cargo.toml -p mnote-web evidence_search_route_prefers_sqlite_index -- --test-threads=1`。 - 验证:`cargo test --manifest-path rust/Cargo.toml -p mnote-web evidence_sqlite_query_returns_locator_results -- --test-threads=1`。 - 验证:`cargo test --manifest-path rust/Cargo.toml -p mnote-web evidence_index_parses_resource_body_with_liteparse_sidecar -- --test-threads=1`。 ### 19.5 搜索与读回 - [x] 新增 `mnote.evidence.search` 工具合同。 - [x] 新增 `mnote.evidence.read` 工具合同。 - [x] 新增 `mnote.evidence.open` 工具合同。 - [x] 新增 `mnote.evidence.search` route / runtime 执行。 - [x] 新增 `mnote.evidence.read` route / runtime 执行。 - [x] 新增 `mnote.evidence.open` route / runtime 执行。 - [x] 旧 `docs_search` / `docs_read` 兼容转发到 evidence tool。 - [x] search 结果必须返回 quote + locator + openAction。 - [x] read 必须返回上下文窗口和同 section 周边证据。 - [x] open 只做定位归一化,不让 agent 自己拼 URL。 验收: - search 命中后可以直接点击跳转。 - read 结果可以作为 agent 回答引用,不需要二次猜测。 2026-06-03 首刀证据: - 已新增 `/api/evidence/search`,复用 local-folder search/OCR 索引并输出 `EvidenceSearchResponse`。 - OCR 命中会优先使用 `ocrEvidence.sourceRootRelativePath` 作为真实 resourcePath,并从 `ocrEvidence.ocrRootRelativePath` 推导 `*.source-map.json`,返回真实图片/PDF resourceKind、page、bbox、charRange 和 openAction params。 - 已新增 `/api/evidence/read` 和 `/api/evidence/open` 最小 route。`read` 目前仍基于现有 local search 上下文回填,后续需要接 source-map / evidence block 后才能满足 section 周边证据验收。 - Hermes tool runtime 已接入 `mnote.evidence.search/read/open`,不再只是 core-protocol 注册。 - `/api/search/documents` 的 local_folder 路径已补回 `evidence` 与 `source.locator`,旧兼容面至少能看到可回跳证据。 - Hermes runtime 已补旧 `docs_search` / `docs_read` 兼容:`docs_search` 转到 `mnote.evidence.search`,`docs_read` 带 locator 时转到 `mnote.evidence.read`,旧 `documentId` 读法保留并附加 locator。 - `/api/evidence/search` 已优先查询 `.mnote/index/evidence.sqlite`,命中 SQLite OCR/resource block 后仍会回读 `*.source-map.json` 补 page、bbox、blockId、charRange 和 openAction params。 - `/api/evidence/read` 已优先基于 locator 读 `*.source-map.json`,按 blockId 返回前后 blocks,并补入同 section 的周边 blocks;无 source-map 时回退到 evidence.sqlite 的同 owner 上下文窗口,再回退旧 local search。 - 验证:`cargo test --manifest-path rust/Cargo.toml -p mnote-web evidence -- --test-threads=1`。 - 验证:`cargo test --manifest-path rust/Cargo.toml -p mnote-web evidence_sqlite_read_context_returns_anchor_block -- --test-threads=1`。 - 验证:`cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_legacy_docs -- --test-threads=1`。 ### 19.6 UI 侧回跳 - [x] resource tab 支持按 locator 打开 PDF 页。 - [x] resource tab 支持 bbox 高亮。 - [x] Markdown 支持 heading / line 定位。 - [x] owner page 和资源页使用同一 locator。 - [x] 结果列表里不要暴露内部 cache id 作为唯一入口。 - [x] 侧栏、搜索结果和 agent citation 使用同一跳转合同。 验收: - 用户点结果可以进入正确页码或正确位置。 - 同一条证据在 UI、agent 和索引中的展示一致。 2026-06-03 首刀证据: - 搜索结果行已携带 `data-evidence-locator`,点击时不再只依赖内部 cache id;PDF / 图片 locator 会通过 `openLocalResourceInActiveTab` 打开 resource tab,Markdown locator 会把 `blockId` / `page` / `bbox` / `sourceMapPath` 带入文档 URL。 - resource tab 已消费 `EvidenceLocator`:面板记录 `data-mnote-evidence-*`,PDF iframe 会把 `page` / `bbox` / `blockId` 传给 `/pdf-preview`,图片资源会绘制 bbox overlay,Markdown/text/code resource tab 会按 `blockId` 滚动并高亮。 - `/pdf-preview` 已支持 `page` / `bbox` / `blockId` query,渲染目标页时会标记页 canvas、绘制 bbox highlight 并滚到目标页。 - Markdown evidence index 已按 heading/非空行生成 evidence blocks,locator 带 `sectionPath`、`lineRange`、`blockId`;文档页主编辑器已支持从 URL 读取 `blockId` / `lineRange` 并对对应 `data-block-id` 做滚动和高亮。 - 验证:`cargo test --manifest-path rust/Cargo.toml -p mnote-web pdf_preview_page_does_not_render_visible_toolbar -- --test-threads=1`。 - 验证:`cargo test --manifest-path rust/Cargo.toml -p mnote-web document_shell_returns_page_aggregate_snapshot -- --test-threads=1`。 - 验证:`cargo test --manifest-path rust/Cargo.toml -p mnote-web evidence_sqlite_query_returns_locator_results -- --test-threads=1`。 - 验证:`node --check rust/crates/mnote-web/browser/document-resource-tab-runtime.js`、`node --check rust/crates/mnote-web/browser/sidebar-tree-runtime.js`、`node --check rust/crates/mnote-web/browser/sidebar-filetree-open-runtime.js`、`node --check rust/crates/mnote-web/browser/document-editor-adapter-runtime.js`。 ### 19.7 图谱投影 - [x] 先用 SQLite edge table 表达 deterministic relation。 - [x] 先支持 `contains` / `links_to` / `resource_refers_to` 这类稳定边。 - [x] 接入 `mentions` entity edge 抽取。 - [x] 只有 locator 能回溯的边才能进入 graph。 - [x] LadybugDB 只做 projection,不做 source of truth。 - [x] graph traversal 结果必须带证据引用。 - [x] graph 删除后不影响搜索主链。 验收: - 图谱可删可重建。 - 图谱回答不会脱离 evidence locator。 2026-06-03 首刀证据: - evidence.sqlite 写入时已从 Markdown `backlinks` / `resourceRefs` 生成确定性边:`markdown_links_to`、`resource_refers_to`、`document_contains_resource`。 - deterministic edge 的 `source_block_id` 指向对应 Markdown body evidence block,`insert_evidence_edge` 会拒绝没有 locator block 的边;`mentions` 已以 `@Entity` 规则进入 `entity:*` 边。 - `mnote.evidence.search` 的 `mode=graph` 已走 SQLite edge table traversal;返回仍是 `EvidenceSearchResult`,包含 `quote + EvidenceLocator`,因此 graph answer 不会脱离 evidence 引用。 - 当前没有引入 LadybugDB runtime,graph 主链只读 `.mnote/index/evidence.sqlite` 的 edge projection;测试直接删除 `evidence_edge` 后,FTS 搜索仍可命中 evidence blocks,证明 graph projection 删除不影响 search / locator 主链。 - 验证:`cargo test --manifest-path rust/Cargo.toml -p mnote-web local_search_index -- --test-threads=1`。 ### 19.8 Agent 接入 - [x] Hermes / Reasonix prompt 中优先使用 evidence tool。 - [x] agent 回答模板强制带 source title、page / section 和 quote。 - [x] agent 不直接读取 SQLite 或 sidecar 文件。 - [x] agent 不自己拼接 open URL。 - [x] agent 的 run receipt 记录 evidence ids。 验收: - Agent 说出的每个关键结论都能被用户点击回到原文。 - Agent 的检索路径不依赖隐藏的二级真相。 2026-06-03 首刀证据: - 已新增 `skills/mnote-document-evidence/SKILL.md`,Hermes / Reasonix 可见,明确要求优先使用 `mnote.evidence.search/read/open`。 - Hermes tool manifest 已暴露 `mnote.evidence.search/read/open`,运行时 dispatch 到 evidence route helper。 - 2026-06-04 复核补强:`scripts/reasonix-acp-wrapper.mjs` 已注册 `mnote_evidence_search/read/open` 三个 Reasonix ACP 只读工具,并把它们转发到 Rust `mnote.evidence.search/read/open`;wrapper selftest 覆盖 evidence payload 继承 `rootUri` 与 evidence search 只读属性。 - 2026-06-04 真实服务验证:登录测试账号后,`/api/hermes/client/tools?scope=mnote&profile=reasonix` 已返回 `mnote.evidence.search/read/open`;`/api/hermes/client/skills?runtime=mnote&agentId=reasonix` 已返回启用的 `mnote-document-evidence` skill。 - 2026-06-04 索引 skill 合并:公开 skill 改为 `mnote-local-index`,合并 evidence 检索与索引管理说明;`mnote-document-evidence` 仅保留为 `mnote.skill.read` 兼容别名,不再作为公开 skill 摘要展示。新增 `mnote.index.status/refresh/update_settings`,Reasonix ACP 对应 `mnote_index_status/refresh/update_settings`。 - 2026-06-04 真 Reasonix ACP 验证:带 `agentId=reasonix`、`contextRefs=[current_page, folder]`、local-folder `rootUri` 发起 `/api/hermes/client/runs`,SSE 中出现 `tool.started/tool.completed`,工具为 `mnote_evidence_search`,返回 `quote="Printer test page"`、`page=1`、`bbox`、`sourceMapPath` 和 `mnote.agent_run_receipt.evidence.v1`。 - 2026-06-04 修正:Reasonix wrapper 原先用字符串包含 `"error"` 判断工具失败,导致 `error:null` 的成功结果在 UI/SSE 中被标记成 `tool.failed`;已改为解析 JSON,仅 `ok:false` 或非空 `error` 才标记失败。 - Skill 约束明确要求回答保留 quote、source 和 openAction,禁止直接读取 `.mnote/index`、OCR sidecar 或自行拼接 URL。 - 验证:`cargo test --manifest-path rust/Cargo.toml -p mnote-web skill_registry -- --test-threads=1`、`cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_manifest_returns_first_batch_tools -- --test-threads=1`。 - 验证:`node --check scripts/reasonix-acp-wrapper.mjs`。 - 验证:`MNOTE_REASONIX_ACP_SELFTEST=1 node scripts/reasonix-acp-wrapper.mjs`。 - 验证:`node scripts/task528-document-evidence-liteparse-agent-smoke.js`,确认真实 PDF 正文 `Printer test page` 命中 `mnote.evidence.search`,返回 `page=1`、`bbox`、`sourceMapPath`,并在 agent tool audit/run receipt 中记录 evidence id。 - 验证产物:`tmp/task528-document-evidence-liteparse-agent-smoke/reasonix-tools-events.sse`。 ### 19.9 兼容与迁移 - [x] 保留现有 OCR sidecar 约定,不强制迁移存量数据。 - [x] 保留现有 `includeOcr=true` 兼容入口。 - [x] 保留现有 `docs_search` / `docs_read` 兼容壳。 - [x] 新 contract 先增后替,不做硬切。 - [x] 迁移阶段允许 `search-index.json` 和 `evidence.sqlite` 并存,但只能有一个主语义。 验收: - 存量数据不需要先整体重跑就能继续使用。 - 新旧接口同时存在时,主链不会分叉出两套真相。 ### 19.10 不做的事 - [x] 不新增独立 PageIndex runtime。 - [x] 不新增独立 BookRAG runtime。 - [x] 不新增独立 Kwipu runtime。 - [x] 不默认引入 SeekDB。 - [x] 不把 LadybugDB 变成正文或 locator 真相。 - [x] 不把 OCR 文本直接写回 owner Markdown 正文。 - [x] 不让 agent 直接扫 `.mnote` 索引文件。 - [x] 不为 search 主链加轮询刷新。 验收: - 每个新增项目都能回答“它是否减少重复真相”。 - 不能回答时,默认不接入主链。