Files
mnote/design/07-ai/done/7-51-lightrag-post-commit-hardening-v1.md
T

13 KiB
Raw Blame History

7-51 LightRAG post-commit hardening v1

创建时间:2026-06-07

状态:done

2026-07-03 口径回正:当前 runtime 已回到 OpenHub / native agent + LightRAG + Turso/libSQL。本文重新作为当前默认 LightRAG provider 的 hardening 基线;此前 7-68 OpenHub + WeKnora + MNote Page AI 深度融合 中将 WeKnora 设为默认 provider 的口径已标记 stale。

Owner07-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 ADelete retry / orphan doc guard

目标:source 删除或 hash 变化后,即使 LightRAG 删除失败,也不能丢失重试 provider doc idprune 不能隐藏仍可能参与回答的 orphan doc。

Checklist

  • 修改 sync_registry_source_state(...)source missing / hash changed 时不要立即清空 lightRagDocId;应进入 stale=true + lightRagStatus=delete_submitteddelete_retry_required
  • sync_registry_with_documents(...) 调用 LightRAG delete 失败时,把失败写入 registry entry 的可见状态,而不是吞掉后只保留 stale。
  • 只有确认 LightRAG /documents 不再包含该 doc 后,才清空 lightRagDocId 并标记 delete_completed
  • prune_registry 不清理仍带 lightRagDocId 且 delete 未确认完成的 stale entry。
  • mapped_references(...) 对 missing registry 的 provider reference 需要区分:
    • provider orphan / unknown source:默认不作为有效 MNote citation 返回,或明确返回 degraded + unmapped 分类,但不得进入 scoped answer citation。
    • registry 命中但 stale / deleted:继续过滤。
  • delete-source route 保持 delete_file=false,并保留“不删除用户原始 source”的断言。

验证:

  • 单测:LightRAG delete 失败时 registry 保留 doc id 和 retry 状态。
  • 单测:delete completed 后才清 doc id。
  • 单测:prune 不删除 delete_submitted / delete_retry_required entry。
  • 单测:missing registry provider reference 不会作为正常 citation 返回。
  • cargo test -p mnote-web knowledge_rag -- --nocapture

实施记录:

  • 2026-06-07sync_registry_source_state(...) 在 source missing / hash changed 时保留 lightRagDocId,并把状态置为 delete_submitted
  • 2026-06-07sync_registry_with_documents(...) 会重试 delete_submitted / delete_retry_required doc idLightRAG delete 失败时写入 delete_retry_required,成功提交后保持 delete_submitted,等 /documents 消失后才标记 delete_completed 并清空 doc id。
  • 2026-06-07:当前 registry schema 先用 lightRagStatus=delete_retry_required 表达失败状态,不额外扩写错误 message 字段,避免扩大持久化迁移面。

4. Phase BSource scope 语义收紧

目标:避免调用方误以为 sourcePaths 已限制 LightRAG provider 检索范围。

Checklist

  • /api/knowledge-rag/query 返回中新增 sourceScopeMode,当前值明确为 post_filter_mapped_references
  • sourcePaths 非空,默认不向普通 agent / Page AI 暴露未过滤 raw chunks;至少 compact tool output 继续不暴露 raw chunks。
  • HTTP API 如仍保留 raw,必须标注 rawScopeFiltered=false 或等价字段,提醒 raw 未受 source scope 过滤。
  • mnote.knowledge_rag.query manifest / Reasonix wrapper / skill 文案从“限制检索来源”改为“按 MNote source 过滤返回 referencesprovider raw 可能仍为全局检索结果”。
  • Page AI final answer 只允许引用 filtered references/citations,不得引用 raw LightRAG chunks。

验证:

  • 单测:sourcePaths=[alpha]references 只含 alpha。
  • 运行态 smokesourceScopeMode=post_filter_mapped_referencesrawScopeFiltered=false
  • 单测或 wrapper selftestagent compact result 不含 raw chunks。
  • task538-knowledge-rag-source-scope-api-smoke.js 更新并通过。
  • task534-knowledge-rag-source-management-scope-smoke.js UI source management 部分已修复并通过。

实施记录:

  • 2026-06-07/api/knowledge-rag/query 返回 sourceScopeMode=post_filter_mapped_referencesrawScopeFiltered=false
  • 2026-06-07mnote.knowledge_rag.query compact agent result 继续只暴露 filtered references/citations,不暴露 raw.chunks
  • 2026-06-07manifest、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-07task534 修正为打开资料库设置后切到“全部”来源,避免默认“需处理”过滤隐藏已索引 source;在 3300 最新构建通过。

5. Phase CLocator strict match / degradation

目标:没有真实匹配到 quote / chunk 对应 sidecar block 时,不生成看似精确的 page/bbox。

Checklist

  • 修改 find_lightrag_sidecar_block(...):移除或限制 first_positioned_block fallback;只有 quote 与 block content 达到明确匹配阈值时才返回 page/bbox locator。
  • 若只找到 source resource 但没有精确 block match,返回 clickable degraded resourceTab citation,但 locatorDegraded=true
  • citationMarkdown 对 degraded resourceTab 使用稳定文案,例如 来源定位降级:<file>,不包含伪造页码。
  • 对 PDF / image / DOCX fallback citation 分别保留打开能力,但不伪造 bbox。
  • 记录 LightRAG chunk 缺 refs 的当前边界;未来若 provider 暴露 refs,再改为 refs 优先、文本匹配 fallback。

验证:

  • 单测:quote 不匹配 sidecar block 时不返回 page/bbox locator。
  • 单测:quote 匹配 sidecar block 时仍返回 page/bbox locator。
  • 单测:known resource + no locator 返回 clickable degraded citation。
  • task529-knowledge-rag-citation-resource-tab-smoke.js 更新为当前 fixture 可重复的正例,并通过。

实施记录:

  • 2026-06-07find_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-07task529 改为当前 image source 降级 citation 正例,验证 open_reference 与 citation URL 能打开 image resource tab,且不携带伪造 page locator。

6. Phase DAgent / UI degraded citation 口径统一

目标:agent 可以使用 MNote 返回的 degraded citation,但不能编造页码、bbox 或 provider 内部路径。

Checklist

  • 更新 skills/mnote-knowledge-rag/SKILL.mdlocatorDegraded=true 时,可以引用返回的 citationMarkdown,但必须说明来源定位降级;禁止编造 page / bbox。
  • 更新 Reasonix system prompt 中 knowledge-rag 能力说明,保持同一口径。
  • 更新 Page AI final answer smoke,增加 degraded citation 场景:最终回答可以含降级 citation,但不能说成 p.N / bbox。
  • 更新 dashboard smoke,不再依赖固定 Completed (5) / Fail (4) / 固定 doc id;改为验证 Documents / Graph / Retrieval 入口与当前 documents summary 可见。

验证:

  • MNOTE_REASONIX_ACP_SELFTEST=1 node scripts/reasonix-acp-wrapper.mjs
  • node scripts/task530-knowledge-rag-page-ai-final-answer-smoke.js
  • node scripts/task531-lightrag-dashboard-ui-smoke.js

7. Phase EReasonix / manifest drift guard

目标:在完整 7-47 capability registry 实施前,先降低 Reasonix wrapper 与 Rust manifest 的漂移风险。

Checklist

  • 增加一个轻量 selftestRust manifest 中 mnote.knowledge_rag.* 三个工具必须都存在于 Reasonix wrapper 映射。
  • 增加一个反向 selftestReasonix wrapper 暴露的 mnote_knowledge_rag_* 必须能映射到 Rust manifest tool name。
  • 保留手写工具表作为短期现实,但在 7-47 中继续推进 manifest 动态注册。
  • 若发现旧 mnote.evidence.* / mnote.index.* 函数被 grep 误判,给 manifest 源码附近加注释:dead code 仅保留历史对照,不在 manifest vector 中注册。

验证:

  • MNOTE_REASONIX_ACP_SELFTEST=1 node scripts/reasonix-acp-wrapper.mjs
  • cargo test -p mnote-web hermes_client_tools_uses_manifest_and_profile_disabled_state -- --test-threads=1

实施记录:

  • 2026-06-07Reasonix wrapper selftest 会读取 Rust hermes_tools/manifest.rs,校验 mnote.knowledge_rag.* manifest tools 与 wrapper MNOTE_TOOL_NAMES / REASONIX_TOOL_TO_MNOTE_TOOL 双向一致。

8. Phase Flegacy OCR / Convex media visible runtime 退役跟进

目标:LightRAG 成为资料库主线后,继续清掉仍可能被浏览器 runtime 或 worker 误读为 active fallback 的旧 OCR / Convex Files 链路。

Checklist

  • /api/local-folder/events 不再转发 local_ocr.job.updatedresource tab 不再依赖 local OCR SSE 或 synthetic_resource_write 刷新 filetree。
  • UI preference 不再接受 localOcr.* 写入;历史 effective preference 强制为 false / retired。
  • FileTree 右键入口不再保留 local-ocr action alias;资料索引只走 knowledge-rag-index/api/knowledge-rag/ingest
  • 浏览器 runtime 不再调用 /api/media/sign / /api/media/upload;旧 Convex Files 前端链路只标记 retired guard。
  • AppState 移除 local_ocr_job_tx / local_ocr_active_jobs,旧 local OCR helper 不再广播 runtime event。
  • local search incremental refresh 遇到 OCR sidecar 时只清理旧 evidence sqlite 投影,不再重建 OCR evidence。
  • routes/local_ocr.rs 从历史 HTTP job / MinerU runtime 实现收缩为历史 OCR sidecar 识别、frontmatter 解析和索引读取 helper;旧 ignored HTTP route tests 已移除。
  • resource tab 后台任务抽屉、toolbar 与 CSS 从 mnote-local-ocr-* 重命名为 mnote-knowledge-rag-*Knowledge RAG ingest/delete 不再挂旧 OCR DOM / function 名。
  • Page AI 目标包删除空实现的 OCR sidecar context enrichmentlocal-first agent 只携带当前文件/selection/allowed roots,不再保留 ocrContext / ocrRootRelativePath 注入点。
  • Sidebar 旧 open-ocr-settings / toggle-ocr-tasks / data-local-ocr-* 委托移除;历史 .ocr/*.ocr.md sidecar 仅以 retired-ocr-sidecar:* 资源身份打开,不再伪装为 active local OCR。

验证:

  • cargo test -p mnote-web local_ocr -- --test-threads=1
  • cargo test -p mnote-web local_search_ocr_sidecar_is_hidden_after_lightrag_retirement -- --test-threads=1
  • cargo test -p mnote-web -- --test-threads=1
  • cargo test --workspace -- --test-threads=1
  • git diff --check
  • 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/