6.9 KiB
Worker B:7-27 代码/测试缺口审查
审查时间:2026-05-20 审查范围:
doc.rs+hermes_tools.rs+manifest.rs分级:🟢 已满足 / 🟡 可作为后续增强 / 🔴 必须修复才能归档
检查点 1:blocks_to_markdown 是否能从 legacy content/contentNodes 读取文本
结论:🟢 已满足
legacy_block_text() 函数 (doc.rs:973-986) 逐级回退:
fn legacy_block_text(block: &Value) -> String {
if let Some(text) = block.get("text").and_then(Value::as_str) { ... }
if let Some(content) = block.get("content") { return inline_text_value(content); }
if let Some(content_nodes) = block.get("contentNodes") { return inline_text_value(content_nodes); }
}
block_text() (doc.rs:1265-1270) 只读 text 字段用于 markdown 序列化,但 build_page_content 中的 update_legacy_block_text_for_markdown_edit 正确使用了 legacy_block_text 做比较,且写回时通过 replace_single_inline_text_value 递归处理 content/contentNodes 中的 text 字段。
证据: inline_text_value() (doc.rs:988-1000) 递归处理 Array/Object/String 三种形态。
检查点 2:注释格式是否与 7-27 文档一致,是否保留 revisionRef
结论:🟡 可作为后续增强
当前格式:
<!-- block:{id}:{type} -->
<!-- block:{id}:{type}:level={level} --> (heading 块)
7-27 §3.3.1 设计为:
<!-- block:{id}:{type}:{revision_ref} -->
<!-- block:{id}:{type}:{revision_ref}:level={level} --> (with level)
差异:revisionRef 不写入注释,而是从原始 block.revisionRef 读取。解析器 extract_block_comment() 虽然支持 type:rev 格式(splitn(3, ':') 后 parts[2] 可以包含 rev),但 blocks_to_markdown 写回时不输出 rev。
影响: 低。revisionRef 在整个 build_page_content 路径中被正确继承(doc.rs:685-690),只是注释里看不到。不阻碍归档,可后续增强。
检查点 3:full_content 是否不再被拒绝,是否保留复杂块
结论:🟢 已满足
doc_markdown_edit中full_content转为{search: current_md.trim(), replace: full.trim()}单个 operation,进入新路径parse_final_markdown_to_blocks对无注释行创建is_new=true的 paragraph 块build_page_content追加新块并保留原始复杂块(is_complex_markdown_original_block)- 测试
test_build_page_content_full_content_replaces_old_text_blocks_but_keeps_complex_blocks验证复杂块保留 - 集成测试
hermes_tools_markdown_edit_online_full_content_rejects_unsafe_block_mapping注释确认:"7-27 修复后:full_content 不再被拒绝"
检查点 4:dryRun 是否不写入
结论:🟢 已满足
doc_markdown_edit 中:
if input.dry_run == Some(true) {
return Ok(json!({
"written": false,
"dryRun": true,
"diff": changed_blocks
}));
}
本地文件路径也有独立的 dryRun 分支只返回预览。
测试 hermes_tools_markdown_edit_local_dry_run_does_not_write 验证。
检查点 5:selection / allowedTargetBlockIds 是否阻止越界写入
结论:🟢 已满足
ensure_markdown_changed_blocks_within_allowed() (doc.rs:1050-1073) 在写回前检查每个 changedBlocks 中的 blockId 是否在 allowed_block_ids 中。越界时返回 mnote_markdown_edit_target_out_of_scope 错误。
测试 hermes_tools_markdown_edit_rejects_selection_out_of_scope 验证。
selected_block_ids() (doc.rs:1075-1094) 从 selectedBlockIds / allowedTargetBlockIds / selectedBlockId / blockId 四个参数中收集。
检查点 6:旧 build_block_ops_from_markdown_edit 推导路径
结论:🟢 已满足(已退役)
doc.rs:1911 末尾注释:
// 退役:7-27 改为 final_md → blocks → execute_page_body_save_from_aggregate 直接写回
函数体仍保留但不再被任何调用者引用(doc.rs 内只有一处调用已在步骤 4 中被替换)。可用 cargo +nightly deadlinks 确认死代码状态,但已足够安全。
检查点 7:测试覆盖是否足以归档
结论:🟢 已满足
单元测试覆盖(doc.rs 内)
| 测试 | 验证点 |
|---|---|
test_search_replace_exact |
精确匹配替换 |
test_search_replace_normalized_chinese_byte_boundaries |
中文忽略空白 + byte 边界保留 |
test_search_replace_full_content |
全文替换 = 全文精确匹配 |
test_blocks_to_markdown_with_ids |
块 ID 注释输出 |
test_blocks_to_markdown_heading |
heading 类型 + level 注释 |
test_blocks_to_markdown_complex_block_uses_raw_marker |
复杂块 raw marker |
test_build_page_content_full_content_replaces_old_text_blocks_but_keeps_complex_blocks |
full_content 新块 + 复杂块保留 |
test_build_page_content_preserves_missing_original_text_block_when_some_ids_remain |
ID 消失时保留原始块 |
test_build_page_content_preserves_unchanged_inline_content_nodes |
行内 marks 保留(不变时) |
test_build_page_content_preserves_single_inline_node_marks_when_text_changes |
行内 marks 保留(文本改变时) |
集成测试覆盖(hermes_tools.rs)
| 测试 | 验证点 |
|---|---|
hermes_tools_markdown_edit_online_full_content_rejects_unsafe_block_mapping |
full_content 不再拒绝 |
hermes_tools_markdown_edit_merges_same_block_operations |
同块多次操作累积 |
hermes_tools_markdown_edit_maps_normalized_search_to_block |
非精确匹配 + changedBlocks 验证 |
hermes_tools_markdown_edit_online_page_body_save_carries_revision_conflict_key |
revision/conflict key 传递 |
hermes_tools_markdown_edit_rejects_no_applied_operations |
空 operations 拒绝 |
hermes_tools_markdown_edit_rejects_selection_out_of_scope |
selection 越界拒绝 |
hermes_tools_markdown_edit_reports_empty_block_mapping_before_apply |
空 block mapping 错误报告 |
hermes_tools_markdown_edit_shared_read_is_forbidden |
共享文档只读拒绝 |
hermes_tools_markdown_edit_local_dry_run_does_not_write |
local dryRun |
hermes_tools_markdown_edit_local_folder_writes_same_markdown_file |
local folder 写入 |
hermes_tools_markdown_edit_local_requires_write_contract |
local write contract 要求 |
缺口:建议后续增强(非阻塞)
- 无块注释的多段 markdown 还原:当前行级解析器假设每行一个块;多段文本(如代码块)需 GFM fallback(§5.3 有分析但未实现)
revisionRef在注释中可见:当前只在内存中保留,注释格式未输出 rev(§3.3.1 设计差异)build_block_ops_from_markdown_edit函数体删除:当前已退役但函数体仍在文件中
总结
| 分级 | 数量 | 项目 |
|---|---|---|
| 🔴 必须修复才能归档 | 0 | — |
| 🟡 后续增强 | 3 | 注释写 rev, GFM fallback 多段文本, 死代码体删除 |
| 🟢 已满足 | 7/7 | 全部检查点通过 |