Files
mnote/design/05-editor-mainline/done/5-15-local-markdown-path-identity-unification-checklist-v1.md
lix-2026 1956a8a21a chore: align mvp design governance
- 统一 local-first MVP 后阶段架构口径,补充 process 执行总序和 Reasonix 协作记录

- 归档已完成的 design checklist,标注参考型 process,更新 AGENTS/REASONIX/架构文档

- 补充文件树/主编辑器下载与上下文菜单相关实现、bug 记录和 smoke 脚本

验证:git diff --check;codegraph sync .;cargo test -p mnote-web;node --check scripts/task476-filetree-editor-context-menu-download-smoke.js
2026-05-21 09:04:13 +08:00

7.4 KiB
Raw Permalink Blame History

5-15 本地 Markdown 路径身份统一 Checklist v1

状态:done

归档说明(2026-05-21):本地 Markdown 路径身份统一 checklist 已完成并从 process/ 归档到 done/

背景

当前本地 Markdown 主链正在对齐 VS Code 文件模型:普通 .md 文件的运行时身份应来自文件资源地址,而不是 frontmatter 或 MNote 内部稳定 ID。

VS Code 参考:

  • design/05-editor-mainline/reference-code/vscode/src/vs/platform/files/common/fileService.ts
    • createFile(resource)URI 创建文件。
  • design/05-editor-mainline/reference-code/vscode/src/vs/workbench/contrib/files/browser/fileCommands.ts
    • 新建文件后 openEditor({ resource: saveUri })
  • design/05-editor-mainline/reference-code/vscode/src/vs/workbench/contrib/files/browser/editors/fileEditorInput.ts
    • matches() 使用 isEqual(otherInput.resource, this.resource)
  • design/05-editor-mainline/reference-code/vscode/src/vs/workbench/contrib/files/browser/editors/fileEditorHandler.ts
    • working copy 与 editor 是否同一打开项,比较 workingCopy.resourceeditor.resource

本阶段目标不是引入新的稳定语义 ID,而是先消除普通本地 Markdown runtime 中的多 ID 竞争。

身份原则

  • 普通本地 Markdown 的真实身份是 sourceKind + rootUri + relativePath
  • 对外 documentId 继续使用路径型短句柄:local-md:<encoded relative_path>
  • mnote_id 只作为已有 frontmatter 元数据保留,不参与普通本地 Markdown 的 documentId 决策。
  • .mnote/page-ids.json 只允许作为历史兼容/迁移辅助,不参与普通本地 Markdown 的主身份生成。
  • 不主动修改、删除或重写用户 Markdown frontmatter。

允许修改范围

  • rust/crates/mnote-web/src/routes/local_search_index.rs
  • rust/crates/mnote-web/src/routes/local_folder_source.rs
  • 必要时更新直接相关测试:
    • rust/crates/mnote-web/src/routes/search.rs
    • rust/crates/mnote-web/src/routes/tree.rs
    • rust/crates/mnote-web/src/routes/documents.rs

不要修改用户数据目录,不要清理仓库中无关脏文件,不要做 git commit。

P0 Checklist

1. 搜索索引 documentId 与树形列表统一

  • local_search_index.rsindex_markdown_file() 永远按 relative_path 生成 local-md:<encoded relative_path>
  • frontmatter mnote_id 不再生成 local-mdid:*
  • 搜索结果、最近修改、反链接口返回的 Markdown documentId 与文件树一致。
  • mnote_id 的 Markdown 搜索测试必须断言仍返回路径型 ID,例如 local-md:docs~2Fchild.md

验收:

cargo test --manifest-path rust/Cargo.toml -p mnote-web local_search_index -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web search_local_index -- --nocapture

2. 清理本地 Markdown 身份生成的误导参数

  • local_markdown_page_id(relative_path, _mnote_id, _metadata) 不再保留无用参数签名。
  • 普通调用点直接使用 local_markdown_path_page_id(relative_path) 或新的清晰命名函数。
  • 如果必须保留 legacy resolver,函数名必须包含 legacy / compat,并且不能参与普通本地 Markdown 主链。

验收:

rg -n "local_markdown_page_id\\(|local-mdid|mnote_id|page-ids" rust/crates/mnote-web/src/routes/local_folder_source.rs rust/crates/mnote-web/src/routes/local_search_index.rs

期望:

  • local_markdown_page_id( 不应再出现在普通主链调用中。
  • local_search_index.rs 不应再出现 local-mdid 生成逻辑。
  • mnote_id 可以继续出现在解析、兼容测试或“保留 frontmatter”测试中,但不能参与普通 documentId 生成。

3. 不污染用户文件

  • 新建本地 Markdown 不写 mnote_id frontmatter。
  • 复制本地 Markdown 不改写 mnote_id
  • 保存已有 Markdown 时保留原 frontmatter,但不新增身份字段。

验收:

cargo test --manifest-path rust/Cargo.toml -p mnote-web local_tree_command_local_folder_lifecycle -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_page_aggregate_accepts_path_id_when_frontmatter_has_mnote_id -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_save -- --nocapture

P1 Checklist

4. 路径型身份覆盖打开/保存/搜索一致性

  • 同一个含 mnote_id.md 文件,在文件树、页面 aggregate、搜索索引中返回同一个 local-md:<encoded relative_path>
  • documents.content.get / 页面打开不再需要 local-mdid:* 才能命中文件。
  • rename/move 后新路径返回新的路径型 documentId,旧路径型 ID 不作为稳定页面 ID 保留。

验收:

cargo test --manifest-path rust/Cargo.toml -p mnote-web local_markdown_identity_uses_path_even_when_frontmatter_has_mnote_id -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_page_aggregate_accepts_path_id_when_frontmatter_has_mnote_id -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web tree_command_local_folder_lifecycle -- --nocapture

最终验收

cargo fmt --check --all --manifest-path rust/Cargo.toml
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_search_index -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web search_local_index -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_markdown_identity_uses_path_even_when_frontmatter_has_mnote_id -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_page_aggregate_accepts_path_id_when_frontmatter_has_mnote_id -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web tree_command_local_folder_lifecycle -- --nocapture

若涉及浏览器可见行为,Codex 复核阶段必须使用真实浏览器验证并将截图放在 tmp/ 下。

执行状态(2026-05-19

  • P0-1 搜索索引 documentId 已统一为 local-md:<encoded relative_path>,不再由 frontmatter mnote_id 生成 local-mdid:*
  • P0-2 普通本地 Markdown 主链已移除 local_markdown_page_id(relative_path, _mnote_id, _metadata) 误导签名,文件树、page aggregate、find-by-id 改用路径型 ID。
  • P0-3 新建、复制、rename/move/restore/purge 普通本地 Markdown 不再写 .mnote/page-ids.json,也不再写入或改写 mnote_id
  • P1-4 rename/move 后返回新路径型 documentId,旧 ID 不再作为稳定页面 ID 保留。
  • 追加清理:删除 ParsedLocalMarkdownPage.mnote_id 字段,避免后续代码重新把 frontmatter mnote_id 当身份入口。

已通过验收:

cargo fmt --check --all --manifest-path rust/Cargo.toml
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_search_index -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web search_local_index -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_markdown_identity_uses_path_even_when_frontmatter_has_mnote_id -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_page_aggregate_accepts_path_id_when_frontmatter_has_mnote_id -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_page_id_initialization_returns_path_id_without_writing_page_ids -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web tree_command_local_folder -- --nocapture