- add document evidence parsing/search/open routes, Hermes tool wiring, local index settings/status, and the document-evidence skill plus design notes - fix PDF resource tabs by rendering PDFs inline with pdf.js canvases instead of iframe preview pages, release PDF documents on close, and document the fourth-PDF stall bug - keep PDF preview at 2x rendering while removing the previous lazy-load/placeholder direction, and make dev:hot bind loopback defaults externally reachable Verification: - node --check rust/crates/mnote-web/browser/document-resource-tab-runtime.js - node scripts/task-dev-hot-plan-test.js - cargo test -p mnote-web --manifest-path rust/Cargo.toml pdf_preview_page_does_not_render_visible_toolbar - cargo test -p mnote-web --manifest-path rust/Cargo.toml document_shell_returns_page_aggregate_snapshot - cargo build -p mnote-web --manifest-path rust/Cargo.toml - browser smoke: sequentially opened the four tea_seed_oil_cosmetic PDFs; fourth PDF rendered 15/15 canvases, iframeCount=0, browser errors=0
38 KiB
7-46 [process] Document Evidence Retrieval Kernel v1
创建时间:2026-06-03
当前状态:
PROCESSOwner: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、reference-code/seekdb均已单独建 CodeGraph;本文只吸收架构和合同,不把这些项目整体引入运行时。
1. 第一结论
MNote 应建设一个统一的 Document Evidence Retrieval Kernel,作为 Hermes / Reasonix / Page AI 搜索 PDF、Word、图片 OCR、Markdown 和附件内容的唯一证据检索入口。
核心路径:
本地 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 同目录,避免分散到多个项目缓存。
示例:
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 目录:
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
{
"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 选择规则
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 存储
新增或扩展本地索引:
.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 表模型
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:
Document
-> Resource
-> Section
-> Page range
-> EvidenceBlock
Agent 检索时不是只做 BM25,也不是让 LLM 扫全文:
- FTS 快速召回候选 evidence blocks。
- section tree 收拢上下文和页码范围。
- 对长文档问题,可让 LLM 在 section tree 上选择相关 section。
- 再读取 section 内 evidence blocks。
这保留 PageIndex 的“目录树推理”优点,但不引入 PageIndex 的独立文档系统。
8. Graph Retrieval
Graph 是 Evidence Kernel 的投影,不是起点。
8.1 Day-one graph
第一版 graph 先用 SQLite edge table 表达确定性关系:
document_contains_resourceresource_contains_pagepage_contains_blocksection_contains_blockmarkdown_links_toresource_refers_toblock_mentions_entity
这些边都必须能回到 EvidenceLocator。
8.2 LadybugDB projection
当出现以下情况,再引入 LadybugDB:
- 需要 Cypher 做多跳实体关系查询。
- SQLite edge table 查询已经影响交互速度。
- 多文档 entity graph 已有稳定抽取合同。
- 需要 graph traversal 给 agent 提供明确收益。
LadybugDB 只读投影:
evidence.sqlite / source-map artifacts
-> graph projection job
-> .mnote/graph/ladybug/
禁止让 LadybugDB 反向成为 source-map、正文或 locator 真相。
9. Agent Tool Contract
9.1 mnote.evidence.search
请求:
{
"query": "合同解除条件",
"scope": {
"workspaceId": "local:notes",
"rootUri": "file:///mnt/Data1T/notes",
"targetDocumentId": null,
"includeResources": true,
"includeOcr": true
},
"mode": "hybrid",
"topK": 8
}
响应:
{
"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。
展示:
引用 1:Page.md / spec.pdf / 第 3 页 / 第二章 解除条件
点击行为:
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 查询能力。
- 后续可做
SearchBackendprovider。
不采用:
- 当前默认引入。
- 用它替代 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. 实施顺序
这是同一个整体架构的落地顺序,不是多个互相竞争的方案。
- 定义
EvidenceLocator、ParsedResourceArtifact、SourceMapRust 类型和 JSON schema。 - 扩展 MinerU sidecar:从结果 zip 中保留 JSON,写
*.source-map.json。 - 接入 LiteParseProvider:文本 PDF 走 no-OCR parse,输出同一 artifact。
- 建
.mnote/index/evidence.sqlite+ FTS5 + section tree。 - 新增
mnote.evidence.search/read/openroute / tool,并让docs_search/docs_read兼容转发。 - UI resource tab 支持 locator open/highlight。
- Markdown wikilink / resource ref 进入 deterministic edge table。
- 评估 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
pub trait ParseProvider {
fn provider_id(&self) -> &'static str;
fn can_parse(&self, input: &ParseInput) -> ParseCapability;
async fn parse(&self, input: ParseInput) -> Result<ParsedResourceArtifact, ParseError>;
}
Provider 不直接写索引。Provider 只返回 artifact;indexer 统一消费 artifact。
17.2 Search backend trait
pub trait EvidenceSearchBackend {
fn refresh_resource(&self, artifact: &ParsedResourceArtifact) -> Result<()>;
fn search(&self, request: EvidenceSearchRequest) -> Result<EvidenceSearchResponse>;
fn read(&self, locator: EvidenceLocator, context: EvidenceReadContext) -> Result<EvidenceReadResponse>;
}
默认实现是 SQLite FTS。SeekDB 只能作为后续实现之一。
17.3 Graph projection trait
pub trait EvidenceGraphProjection {
fn refresh_edges(&self, edges: Vec<EvidenceEdge>) -> Result<()>;
fn traverse(&self, request: EvidenceGraphRequest) -> Result<EvidenceGraphResponse>;
}
默认实现是 SQLite edge table。LadybugDB 只能作为后续 projection 实现。
18. 最终口径
MNote 的文档问答能力应以 Evidence 为核心,而不是以 OCR、vector、graph 或某个外部 RAG 项目为核心。
判断一个工具能否进入主链,只看三件事:
- 是否能产出或消费 MNote 的 canonical
EvidenceLocator。 - 是否减少重复真相,而不是制造另一套文档库。
- 是否和当前 Rust local-first / Page AI / watcher / resource tab 主链低耦合接入。
按这个标准,当前默认组合是:
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 统一证据合同
- 定义
EvidenceLocatorschema。 - 定义
ParsedResourceArtifactschema。 - 定义
SourceMapschema。 - 定义
EvidenceSearchRequest/EvidenceSearchResponse。 - 定义
EvidenceReadRequest/EvidenceReadResponse。 - 定义
EvidenceEdgeschema。 - 统一 JSON 字段命名,保证 LiteParse / MinerU / Markdown 共用一套定位合同。
- 明确哪些字段是 canonical,哪些字段只是 cache copy。
验收:
- 任一证据都能从 locator 回到 owner 文档或 resource。
- 同一个定位字段不在多个地方各自定义不同语义。
2026-06-03 首刀证据:
- 已新增
rust/crates/core-protocol/src/evidence.rs,导出EvidenceLocator、ResourceSourceMap、ParsedResourceArtifact、EvidenceSearch*、EvidenceRead*、EvidenceEdge。 - 已在
core-protocoltool registry 注册mnote.evidence.search、mnote.evidence.read、mnote.evidence.open只读工具。 - 字段口径:原始文件、owner Markdown、
*.source-map.json与EvidenceLocator是 canonical;search-index.json、未来evidence.sqliterow、graph node/edge 中复制的 page/bbox/text/section 字段都只是 cache copy,必须能从 canonical artifact 重建。 - 验证:
cargo test --manifest-path rust/Cargo.toml -p core-protocol --lib。
19.2 资源解析层
- 实现
ParseProvidertrait。 - 实现
MarkdownParserProvider。 - 实现
LiteParseProvider。 - 复用现有
MinerUProvider路径并输出统一 source-map sidecar。 - 文本型 PDF 默认走
no-ocr。 - 扫描 PDF / 图片默认走 MinerU。
- 解析失败时保留可诊断错误,但不污染正文真相。
- 解析输出必须包含 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,并输出稳定fnv1a64source hash。LiteParseProvider已接入真实lit parse --format json --no-ocrCLI adapter,读取 LiteParse JSON 后生成ParsedResourceArtifact、ResourceSourceMap、page / bbox / section / char range 与 Markdown 输出;测试用 fakelit验证命令调用和 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 落盘
- 确定 sidecar 目录仍沿
{pageStem}.ocr/复用。 - 写入
*.parse.md。 - 写入
*.ocr.md。 - 写入
*.source-map.json。 - 为 source-map 记录 page / bbox / char range。
- 为 source-map 记录 section path。
- 为 source-map 记录 ownerDocumentPath 和 sourceRootRelativePath。
- 为 source-map 记录 provider、modelVersion、sourceHash。
- 保证 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
- 建
.mnote/index/evidence.sqlite。 - 建
evidence_resource表。 - 建
evidence_block表。 - 建
evidence_section表。 - 建
evidence_edge表。 - 建 FTS5 索引。
- 将
search-index.json降级为兼容缓存,不再承载主 evidence 语义。 - 索引写入必须由 artifact 驱动,而不是由 UI 拼装驱动。
- 增量更新优先于全量 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 搜索与读回
- 新增
mnote.evidence.search工具合同。 - 新增
mnote.evidence.read工具合同。 - 新增
mnote.evidence.open工具合同。 - 新增
mnote.evidence.searchroute / runtime 执行。 - 新增
mnote.evidence.readroute / runtime 执行。 - 新增
mnote.evidence.openroute / runtime 执行。 - 旧
docs_search/docs_read兼容转发到 evidence tool。 - search 结果必须返回 quote + locator + openAction。
- read 必须返回上下文窗口和同 section 周边证据。
- 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 侧回跳
- resource tab 支持按 locator 打开 PDF 页。
- resource tab 支持 bbox 高亮。
- Markdown 支持 heading / line 定位。
- owner page 和资源页使用同一 locator。
- 结果列表里不要暴露内部 cache id 作为唯一入口。
- 侧栏、搜索结果和 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/blockIdquery,渲染目标页时会标记页 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 图谱投影
- 先用 SQLite edge table 表达 deterministic relation。
- 先支持
contains/links_to/resource_refers_to这类稳定边。 - 接入
mentionsentity edge 抽取。 - 只有 locator 能回溯的边才能进入 graph。
- LadybugDB 只做 projection,不做 source of truth。
- graph traversal 结果必须带证据引用。
- 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 接入
- Hermes / Reasonix prompt 中优先使用 evidence tool。
- agent 回答模板强制带 source title、page / section 和 quote。
- agent 不直接读取 SQLite 或 sidecar 文件。
- agent 不自己拼接 open URL。
- 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 只读工具,并把它们转发到 Rustmnote.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-evidenceskill。 - 2026-06-04 真 Reasonix ACP 验证:带
agentId=reasonix、contextRefs=[current_page, folder]、local-folderrootUri发起/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 兼容与迁移
- 保留现有 OCR sidecar 约定,不强制迁移存量数据。
- 保留现有
includeOcr=true兼容入口。 - 保留现有
docs_search/docs_read兼容壳。 - 新 contract 先增后替,不做硬切。
- 迁移阶段允许
search-index.json和evidence.sqlite并存,但只能有一个主语义。
验收:
- 存量数据不需要先整体重跑就能继续使用。
- 新旧接口同时存在时,主链不会分叉出两套真相。
19.10 不做的事
- 不新增独立 PageIndex runtime。
- 不新增独立 BookRAG runtime。
- 不新增独立 Kwipu runtime。
- 不默认引入 SeekDB。
- 不把 LadybugDB 变成正文或 locator 真相。
- 不把 OCR 文本直接写回 owner Markdown 正文。
- 不让 agent 直接扫
.mnote索引文件。 - 不为 search 主链加轮询刷新。
验收:
- 每个新增项目都能回答“它是否减少重复真相”。
- 不能回答时,默认不接入主链。