- 统一 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
139 lines
7.4 KiB
Markdown
139 lines
7.4 KiB
Markdown
# 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.resource` 与 `editor.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.rs` 中 `index_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`。
|
||
|
||
验收:
|
||
|
||
```bash
|
||
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 主链。
|
||
|
||
验收:
|
||
|
||
```bash
|
||
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,但不新增身份字段。
|
||
|
||
验收:
|
||
|
||
```bash
|
||
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 保留。
|
||
|
||
验收:
|
||
|
||
```bash
|
||
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
|
||
```
|
||
|
||
## 最终验收
|
||
|
||
```bash
|
||
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)
|
||
|
||
- [x] P0-1 搜索索引 `documentId` 已统一为 `local-md:<encoded relative_path>`,不再由 frontmatter `mnote_id` 生成 `local-mdid:*`。
|
||
- [x] P0-2 普通本地 Markdown 主链已移除 `local_markdown_page_id(relative_path, _mnote_id, _metadata)` 误导签名,文件树、page aggregate、find-by-id 改用路径型 ID。
|
||
- [x] P0-3 新建、复制、rename/move/restore/purge 普通本地 Markdown 不再写 `.mnote/page-ids.json`,也不再写入或改写 `mnote_id`。
|
||
- [x] P1-4 rename/move 后返回新路径型 `documentId`,旧 ID 不再作为稳定页面 ID 保留。
|
||
- [x] 追加清理:删除 `ParsedLocalMarkdownPage.mnote_id` 字段,避免后续代码重新把 frontmatter `mnote_id` 当身份入口。
|
||
|
||
已通过验收:
|
||
|
||
```bash
|
||
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
|
||
```
|