Files
mnote/.codex/reasonix-tasks/results/batch-i-worker-b-7-27-code-test-gap.md
T

6.9 KiB
Raw Blame History

Worker B7-27 代码/测试缺口审查

审查时间:2026-05-20 审查范围:doc.rs + hermes_tools.rs + manifest.rs 分级:🟢 已满足 / 🟡 可作为后续增强 / 🔴 必须修复才能归档


检查点 1blocks_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),只是注释里看不到。不阻碍归档,可后续增强。


检查点 3full_content 是否不再被拒绝,是否保留复杂块

结论:🟢 已满足

  • doc_markdown_editfull_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 不再被拒绝"

检查点 4dryRun 是否不写入

结论:🟢 已满足

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 验证。


检查点 5selection / 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 要求

缺口:建议后续增强(非阻塞)

  1. 无块注释的多段 markdown 还原:当前行级解析器假设每行一个块;多段文本(如代码块)需 GFM fallback(§5.3 有分析但未实现)
  2. revisionRef 在注释中可见:当前只在内存中保留,注释格式未输出 rev(§3.3.1 设计差异)
  3. build_block_ops_from_markdown_edit 函数体删除:当前已退役但函数体仍在文件中

总结

分级 数量 项目
🔴 必须修复才能归档 0
🟡 后续增强 3 注释写 rev, GFM fallback 多段文本, 死代码体删除
🟢 已满足 7/7 全部检查点通过