---
phase: 10-restructure
plan: 02
type: execute
wave: 2
depends_on:
  - 10-01
files_modified:
  - src/parser.rs
  - src/parser/mod.rs
  - src/parser/builder.rs
  - src/parser/iterator.rs
  - src/parser/encoding.rs
  - tests/parser_coverage.rs
  - tests/performance_metrics.rs
  - tests/edge_cases.rs
  - tests/sqllog_additional.rs
  - tests/parser_errors.rs
autonomous: true
requirements:
  - REFACTOR-01
  - REFACTOR-02
  - REFACTOR-05

must_haves:
  truths:
    - "src/parser.rs 已被删除（被拆分为 src/parser/ 子目录的四个文件）"
    - "src/parser/mod.rs 含 LogParser 结构体、impl LogParser、pub(crate) parse_record 函数、私有 parse_record_with_hint 函数、静态 FINDER_CLOSE_META / FINDER_RECORD_START"
    - "src/parser/builder.rs 含 LogParserBuilder 结构体与其完整 impl"
    - "src/parser/iterator.rs 含 LogIterator 结构体、impl LogIterator、Iterator trait 实现、is_timestamp_start / make_invalid_format_error 私有函数；LogIterator::filter_by_exec_time 与 filter_by_sql_contains 保持 pub 可见性并委托调用 filter::adapter"
    - "src/parser/encoding.rs 含 pub enum FileEncodingHint"
    - "src/parser/mod.rs 通过 `pub use encoding::FileEncodingHint;` 将枚举提升到 parser 模块层"
    - "原 tests/ 中直接依赖 parse_record 的测试已迁入 src/parser/mod.rs 的 #[cfg(test)] mod tests 块；仅使用公开 API 的测试保留在 tests/"
    - "cargo test 全量通过；cargo build --examples 通过"
  artifacts:
    - path: "src/parser/mod.rs"
      provides: "LogParser、parse_record(pub(crate))、parse_record_with_hint(私有)、静态 finder"
      contains: "pub struct LogParser"
    - path: "src/parser/builder.rs"
      provides: "LogParserBuilder 完整 impl"
      contains: "pub struct LogParserBuilder"
    - path: "src/parser/iterator.rs"
      provides: "LogIterator + Iterator impl + filter_by_* 委托 + is_timestamp_start"
      contains: "pub struct LogIterator"
    - path: "src/parser/encoding.rs"
      provides: "pub enum FileEncodingHint"
      contains: "pub enum FileEncodingHint"
  key_links:
    - from: "src/parser/iterator.rs"
      to: "src/filter/adapter.rs"
      via: "crate::filter::adapter::filter_by_exec_time/filter_by_sql_contains 委托调用"
      pattern: "adapter::filter_by_(exec_time|sql_contains)"
    - from: "src/parser/mod.rs"
      to: "src/parser/encoding.rs"
      via: "pub use encoding::FileEncodingHint"
      pattern: "pub use encoding::FileEncodingHint"
    - from: "src/parser/builder.rs LogParserBuilder::build"
      to: "src/parser/mod.rs LogParser struct"
      via: "super::LogParser"
      pattern: "super::LogParser"
---

<objective>
将 src/parser.rs（521 行单文件）按 D-01 拆分为 src/parser/ 子目录下的四个文件，并将直接依赖 pub(crate) parse_record 的集成测试迁入内部 #[cfg(test)] 块（D-04），同时把 filter_by_exec_time / filter_by_sql_contains 改为委托调用 filter::adapter 中的泛型版本（D-06、D-07 修订）。

Purpose: 实现 REFACTOR-01（parser/ 子模块容纳所有解析代码）、REFACTOR-02（filter/ 子模块容纳过滤逻辑骨架）、REFACTOR-05（is_timestamp_start 等字节工具函数私有化到 iterator.rs，不出现在公开 API）。

Output: src/parser.rs 文件删除；src/parser/mod.rs、builder.rs、iterator.rs、encoding.rs 四文件填充实际代码；五个 tests/ 文件中调用 parse_record 的测试用例已迁移；cargo test 全量通过；cargo build --examples 通过。

D-07 修订说明：CONTEXT.md 原决策 D-07 要求 LogIterator::filter_by_exec_time 与 filter_by_sql_contains 降为 pub(crate)。RESEARCH.md Pitfall 5 与 PATTERNS.md「Pitfall 5」指出 examples/filter_slow_queries.rs 直接调用 filter_by_exec_time —— 降为 pub(crate) 后 examples 无法编译，违反 REFACTOR-07。**本计划采纳 RESEARCH 推荐方案**：LogIterator 上的两个方法保持 pub 可见性（不变）；filter/adapter.rs 中的底层泛型函数为 pub(crate)（D-06 保持）；lib.rs 不重导出 adapter 中的函数（D-08 保持）。后续 Phase 11 引入 FilterBuilder 后，可决定是否将 LogIterator 上的便捷方法 deprecate。该修订记录在 SUMMARY.md 中。
</objective>

<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/phases/10-restructure/10-CONTEXT.md
@.planning/phases/10-restructure/10-RESEARCH.md
@.planning/phases/10-restructure/10-PATTERNS.md
@.planning/phases/10-restructure/10-01-SUMMARY.md
@src/parser.rs
@src/record.rs
@src/error.rs
@src/filter/adapter.rs
@src/lib.rs
@tests/parser_coverage.rs
@tests/performance_metrics.rs
@tests/edge_cases.rs
@tests/sqllog_additional.rs
@tests/parser_errors.rs

<interfaces>
本计划开始时（继承 10-01 状态）：
- src/parser.rs 仍是 521 行单文件，已将 sqllog:: 替换为 record::
- src/parser/{mod.rs, builder.rs, iterator.rs, encoding.rs} 为占位文件（仅文档注释）
- src/lib.rs 仍声明 `pub(crate) mod parser;` 并 `pub use parser::{ FileEncodingHint, LogIterator, LogParser, LogParserBuilder, parse_record };`

关键类型（来自 src/parser.rs 当前内容，迁移后位置）：

```
src/parser/encoding.rs:
  pub enum FileEncodingHint { Auto, Utf8, Gb18030 }
  （Copy, Clone, Debug, PartialEq, Eq, Default 派生；#[default] 在 Auto）

src/parser/builder.rs:
  pub struct LogParserBuilder { path: PathBuf, encoding_hint: Option<FileEncodingHint> }
  impl LogParserBuilder {
    pub fn new<P: AsRef<Path>>(path: P) -> Self
    pub fn encoding_hint(mut self, hint: FileEncodingHint) -> Self
    pub fn build(self) -> Result<LogParser, ParseError>
  }

src/parser/iterator.rs:
  pub struct LogIterator<'a> { data: &'a [u8], pos: usize, encoding: FileEncodingHint, line_number: u64 }
  impl<'a> LogIterator<'a> {
    pub fn skip_errors(self) -> impl Iterator<Item = Sqllog> + 'a
    pub fn filter_by_exec_time(self, min_ms: u64) -> impl Iterator<Item = Result<Sqllog, ParseError>> + 'a  // 保持 pub
    pub fn filter_by_sql_contains(self, pattern: &str) -> impl Iterator<Item = Result<Sqllog, ParseError>> + 'a  // 保持 pub
  }
  impl<'a> Iterator for LogIterator<'a> { type Item = Result<Sqllog, ParseError>; ... }
  fn is_timestamp_start(bytes: &[u8]) -> bool  // 私有
  fn make_invalid_format_error(raw_bytes: &[u8], line_number: u64) -> ParseError  // 私有
  + 常量 LO_MASK / LO_EXPECTED / HI_MASK / HI_EXPECTED

src/parser/mod.rs:
  pub mod builder;
  pub mod iterator;
  pub(crate) mod encoding;
  pub use builder::LogParserBuilder;
  pub use iterator::LogIterator;
  pub use encoding::FileEncodingHint;
  pub struct LogParser { data: Vec<u8>, encoding: FileEncodingHint }   // 字段允许 pub(super) 以让 builder.rs::build() 构造
  impl LogParser { pub fn iter(&self) -> LogIterator<'_> }
  pub(crate) fn parse_record(record_bytes: &[u8]) -> Result<Sqllog, ParseError>   // 注意：pub → pub(crate)（D-03）
  fn parse_record_with_hint(...) -> Result<Sqllog, ParseError>   // 私有
  static FINDER_CLOSE_META, FINDER_RECORD_START
  #[cfg(test)] mod tests { ... }   // 迁入的测试
```

跨模块路径规范：
- iterator.rs 调用：`use crate::filter::adapter;` + `adapter::filter_by_exec_time(self, min_ms)`
- iterator.rs 调用 parse_record_with_hint：`use crate::parser::parse_record_with_hint;` 或 `super::parse_record_with_hint`（mod.rs 中需让其至少 pub(super)）
- builder.rs 构造 LogParser：`super::LogParser { data, encoding }`（同模块树，可访问私有字段；或在 mod.rs 中将 LogParser 字段标 `pub(super)`）
</interfaces>
</context>

<tasks>

<task type="auto">
  <name>Task 1: 拆分 src/parser.rs，填充 parser/encoding.rs、builder.rs、iterator.rs、mod.rs；让 LogIterator 委托调用 filter::adapter</name>
  <files>src/parser/encoding.rs, src/parser/builder.rs, src/parser/iterator.rs, src/parser/mod.rs, src/parser.rs</files>
  <read_first>
    - src/parser.rs（完整 521 行，所有待拆分代码的唯一权威来源）
    - src/filter/adapter.rs（确认泛型函数签名与可见性）
    - src/record.rs（确认 Sqllog 字段与 parse_meta_from_bytes / parse_indicators_from_bytes / find_indicators_split 签名）
    - src/error.rs（ParseError 变体）
    - .planning/phases/10-restructure/10-PATTERNS.md（每个子文件的精确代码骨架）
    - .planning/phases/10-restructure/10-RESEARCH.md（Architecture Patterns 节 + Anti-Patterns 节）
  </read_first>
  <action>
    严格按以下顺序填充四个文件，每填充完一个立即 `cargo check` 验证（不要等到全部完成才编译）。本任务结束前 src/parser.rs 必须被删除。

    1. **src/parser/encoding.rs**（最小，先做）：
       - 仅含 `pub enum FileEncodingHint` 及其派生与文档注释，整段拷贝自 src/parser.rs lines 21-31。
       - 无 imports。

    2. **src/parser/builder.rs**：
       - imports: `use std::fs;`、`use std::path::{Path, PathBuf};`、`use std::str;`、`use crate::error::ParseError;`、`use crate::parser::encoding::FileEncodingHint;`、`use crate::parser::LogParser;`（mod.rs 会 pub use 它，但更稳的是 `use super::LogParser;`）
       - 整段拷贝 src/parser.rs lines 42-87（LogParserBuilder struct + 完整 impl）。
       - build() 中 `Ok(LogParser { data, encoding })` 要求 LogParser 字段对 builder.rs 可见 —— 由 mod.rs 用 `pub(super)` 标 LogParser 字段（见下方步骤 4），不需要 builder.rs 做任何 workaround。

    3. **src/parser/iterator.rs**：
       - imports:
         ```
         use memchr::memchr;
         use memchr::memmem::Finder;
         use std::sync::LazyLock;
         use crate::error::ParseError;
         use crate::filter::adapter;
         use crate::parser::encoding::FileEncodingHint;
         use crate::record::Sqllog;
         use super::parse_record_with_hint;   // 引用 mod.rs 中私有但 pub(super) 提升的函数
         ```
       - 拷贝 src/parser.rs lines 102-203（LogIterator struct + impl<'a> LogIterator<'a> 含 skip_errors / filter_by_exec_time / filter_by_sql_contains + impl<'a> Iterator for LogIterator<'a>）。
       - **关键修订**：将 filter_by_exec_time 和 filter_by_sql_contains 的方法体改为委托调用：
         ```
         pub fn filter_by_exec_time(self, min_ms: u64) -> impl Iterator<Item = Result<Sqllog, ParseError>> + 'a {
             adapter::filter_by_exec_time(self, min_ms)
         }
         pub fn filter_by_sql_contains(self, pattern: &str) -> impl Iterator<Item = Result<Sqllog, ParseError>> + 'a {
             adapter::filter_by_sql_contains(self, pattern)
         }
         ```
         注意：方法保持 `pub`（D-07 修订决议见 objective）；skip_errors 不变。
       - 在 iterator.rs 中也需要 `static FINDER_RECORD_START: LazyLock<Finder<'static>> = LazyLock::new(|| Finder::new(b"\n20"));`，因为 Iterator::next 内部使用它（src/parser.rs line 19）。
       - 拷贝 src/parser.rs lines 412-437 的常量 LO_MASK / LO_EXPECTED / HI_MASK / HI_EXPECTED + 函数 is_timestamp_start + make_invalid_format_error 到此文件末尾（D-02 就近原则，REFACTOR-05 要求私有不暴露）。
       - 拷贝 src/parser.rs lines 441-487 中关于 is_timestamp_start 的所有测试到 iterator.rs 末尾 `#[cfg(test)] mod tests` 块（这些测试就近覆盖 is_timestamp_start）。

    4. **src/parser/mod.rs**：
       - 顶部模块声明与重导出：
         ```
         pub mod builder;
         pub mod iterator;
         pub(crate) mod encoding;

         pub use builder::LogParserBuilder;
         pub use iterator::LogIterator;
         pub use encoding::FileEncodingHint;
         ```
       - imports（用于本文件内 parse_record_with_hint 和 LogParser 等）：
         ```
         use memchr::memmem::Finder;
         use memchr::{memchr, memrchr};
         use std::str;
         use std::sync::LazyLock;
         use crate::error::ParseError;
         use crate::record::{self, Sqllog};
         use encoding::all::GB18030;
         use encoding::{DecoderTrap, Encoding};
         ```
       - `static FINDER_CLOSE_META: LazyLock<Finder<'static>> = LazyLock::new(|| Finder::new(b") "));`
       - LogParser struct（拷贝自 src/parser.rs lines 33-40，字段改为 `pub(super)` 以允许 builder.rs 构造）：
         ```
         pub struct LogParser {
             pub(super) data: Vec<u8>,
             pub(super) encoding: FileEncodingHint,
         }
         ```
       - impl LogParser（拷贝 src/parser.rs lines 89-99）。
       - `pub(crate) fn parse_record(record_bytes: &[u8]) -> Result<Sqllog, ParseError>` —— **D-03**：可见性由原 `pub` 降为 `pub(crate)`。
       - `pub(super) fn parse_record_with_hint(record_bytes: &[u8], encoding_hint: FileEncodingHint, line_number: u64) -> Result<Sqllog, ParseError>` —— 提升为 pub(super) 让 iterator.rs 可调用；内容拷贝自 src/parser.rs lines 213-410，**但保留 `make_invalid_format_error` 调用** —— 这个函数现在在 iterator.rs 中私有；解决方案：将 make_invalid_format_error 从 iterator.rs 改放到 mod.rs（仍私有，因为只在 mod.rs 内被 parse_record_with_hint 调用，并在 iterator.rs 中通过 `super::make_invalid_format_error` 引用）。重新规划：make_invalid_format_error 放 mod.rs（私有 `fn`），is_timestamp_start 与四个常量放 iterator.rs（私有，被 Iterator::next 使用），iterator.rs 中需要 make_invalid_format_error 时通过 `super::make_invalid_format_error` 调用。
       - 测试模块（迁入 tests/ 的内容，由任务 2 完成填充；本任务先放空骨架）：
         ```
         #[cfg(test)]
         mod tests {
             use super::*;
             // 任务 2 填充：从 tests/performance_metrics.rs、tests/parser_coverage.rs、
             // tests/edge_cases.rs、tests/sqllog_additional.rs、tests/parser_errors.rs 迁入
             // 直接调用 parse_record 的测试用例
         }
         ```

    5. **删除 src/parser.rs**：用 `git rm src/parser.rs`（其全部内容已分散到上述四个文件）。

    6. **lib.rs 临时调整**：在本任务结束时 lib.rs 仍写 `pub use parser::{ FileEncodingHint, LogIterator, LogParser, LogParserBuilder, parse_record };`。但因 parse_record 现在是 pub(crate)，`pub use parser::parse_record` 会编译失败（不能 re-export 非 pub item）。**本任务在 lib.rs 的 pub use 列表中临时移除 parse_record**（仅这一项变更），保留 FileEncodingHint / LogIterator / LogParser / LogParserBuilder 的重导出。lib.rs 其他部分（rustdoc 注释、mod 声明）不变。这一步实现 D-14。

    7. **最终编译验证**：`cargo check` 必须通过。`cargo build --tests` 可能因 tests/ 中残留 `use dm_database_parser_sqllog::parse_record;` 而失败 —— 不要在本任务修复（这是 Pitfall 2，由任务 2 通过测试迁移修复）；只要 `cargo check` （不含 tests）通过即可。

    禁止：本任务不修改 tests/ 中任何文件；不修改 examples/；不动 src/filter/、src/async_api/、src/record.rs、src/error.rs；不在 lib.rs 中添加 `mod filter;`。
  </action>
  <verify>
    <automated>cd /Users/guang/Projects/dm-database-parser-sqllog && ! test -e src/parser.rs && test -f src/parser/mod.rs && test -f src/parser/builder.rs && test -f src/parser/iterator.rs && test -f src/parser/encoding.rs && cargo check 2>&1 | tail -5</automated>
  </verify>
  <acceptance_criteria>
    - src/parser.rs 不再存在；`git status` 显示 `D src/parser.rs`
    - src/parser/mod.rs 含 `pub struct LogParser`，且 `grep -c 'pub(crate) fn parse_record' src/parser/mod.rs` 返回 1
    - src/parser/mod.rs 含 `pub use encoding::FileEncodingHint;` 与 `pub use builder::LogParserBuilder;` 与 `pub use iterator::LogIterator;`
    - src/parser/mod.rs 不再含 `pub fn parse_record`（不是 pub）：`grep -E '^pub fn parse_record\\b' src/parser/mod.rs` 无匹配
    - src/parser/iterator.rs 含 `pub struct LogIterator<'a>` 与 `impl<'a> Iterator for LogIterator<'a>`
    - src/parser/iterator.rs 含 `adapter::filter_by_exec_time(self, min_ms)` 与 `adapter::filter_by_sql_contains(self, pattern)`（委托调用）
    - src/parser/iterator.rs 不含完整的过滤 closure（已委托）：`grep -c 'sqllog.exectime >= threshold' src/parser/iterator.rs` 返回 0
    - src/parser/iterator.rs 含 `fn is_timestamp_start` 且无 `pub` 前缀（REFACTOR-05）：`grep -E '^(pub )?fn is_timestamp_start' src/parser/iterator.rs` 不应匹配 `pub`
    - src/parser/builder.rs 含 `pub struct LogParserBuilder` 与完整三方法 impl
    - src/parser/encoding.rs 含 `pub enum FileEncodingHint` 与 #[default] Auto
    - src/lib.rs 的 pub use 列表已移除 `parse_record`：`grep -c 'parse_record' src/lib.rs` 返回 0
    - `cargo check` 退出码 0（tests 编译可能因 Pitfall 2 失败，由任务 2 修复）
  </acceptance_criteria>
  <done>
    src/parser.rs 已删除，代码完整迁移到 src/parser/ 子目录四个文件；LogIterator 的两个过滤方法委托调用 filter::adapter；is_timestamp_start 与 make_invalid_format_error 已私有化；cargo check 通过。tests/ 与 examples/ 由任务 2 处理。
  </done>
</task>

<task type="auto">
  <name>Task 2: 迁移直接依赖 parse_record 的测试到 src/parser/mod.rs #[cfg(test)] 块，清理 tests/ 中残留的 parse_record 引用</name>
  <files>src/parser/mod.rs, tests/parser_coverage.rs, tests/performance_metrics.rs, tests/edge_cases.rs, tests/sqllog_additional.rs, tests/parser_errors.rs</files>
  <read_first>
    - tests/performance_metrics.rs（全部 16 个测试，全部迁移）
    - tests/parser_coverage.rs（3 个 parse_record 测试需迁移，2 个保留）
    - tests/edge_cases.rs（3 个 parse_record 测试需迁移，1 个保留）
    - tests/sqllog_additional.rs（全文件，全部使用 parse_record；含 GB18030 用例）
    - tests/parser_errors.rs（仅 test_parse_record_timestamp_validation 一个需迁移，其余 8 个保留）
    - src/parser/mod.rs（任务 1 创建的 #[cfg(test)] mod tests 骨架）
    - .planning/phases/10-restructure/10-RESEARCH.md（Test Migration Map 节）
    - .planning/phases/10-restructure/10-PATTERNS.md（Tests Migration Map 节）
  </read_first>
  <action>
    迁移规则（严格遵循 Test Migration Map）：
    - 迁入 src/parser/mod.rs `#[cfg(test)] mod tests` 块的测试：在该测试函数体内将 `dm_database_parser_sqllog::parse_record(...)` / `parse_record(...)`（从 use 引入的）改为 `super::parse_record(...)`，因为内部测试模块通过 `use super::*;` 已能访问 pub(crate) parse_record。
    - 保留在 tests/ 的测试：仅删除 `use dm_database_parser_sqllog::parse_record;` 这条 use（如果文件其他测试用到 parse_record 就一并迁移；否则只移除 use）。
    - 不修改任何测试用例的断言、输入数据、辅助 fn —— 仅修改 `parse_record(...)` 调用前缀和文件归属。

    **逐文件操作清单**：

    1. **tests/performance_metrics.rs**（全部 16 个测试全部迁移）：
       - 整文件 16 个测试函数（performance_metrics_full 等）原样迁入 src/parser/mod.rs 的 #[cfg(test)] mod tests 块（追加在任务 1 已有的 is_timestamp_start 测试的兄弟位置）。
       - 在迁入版本中：移除 `use dm_database_parser_sqllog::parse_record;` 这条 use；`parse_record(&raw)` 调用全部保持原样（因为 `use super::*;` 已引入 pub(crate) parse_record）。
       - 迁移完成后删除 tests/performance_metrics.rs 整个文件：`git rm tests/performance_metrics.rs`。

    2. **tests/parser_coverage.rs**（63 行，分两部分）：
       - 迁入 src/parser/mod.rs 内部：parse_record_single_line_no_newline、parse_record_no_meta_open_paren、parse_record_no_meta_close_paren 三个函数。
       - 保留在 tests/parser_coverage.rs：iterator_skips_leading_blank_line、crlf_in_multiline_first_line。
       - 修改 use 语句：将 `use dm_database_parser_sqllog::{LogParserBuilder, parse_record};` 改为 `use dm_database_parser_sqllog::LogParserBuilder;`（移除 parse_record）。

    3. **tests/edge_cases.rs**（42 行）：
       - 迁入 src/parser/mod.rs 内部：meta_closing_paren_without_space_then_body_on_next_line、appname_empty_then_take_next_token_as_appname_not_ip、indicators_not_strictly_formatted_should_not_split_body。
       - 保留在 tests/edge_cases.rs：probable_record_start_line_and_iterator_singleline_detection。
       - 修改 use：`use dm_database_parser_sqllog::{LogParserBuilder, parse_record};` → `use dm_database_parser_sqllog::LogParserBuilder;`。

    4. **tests/sqllog_additional.rs**（233 行，全文件全部使用 parse_record）：
       - 整文件所有测试函数迁入 src/parser/mod.rs 内部测试块（含 body_without_indicators、indicators_exec_id_only、GB18030 测试等）。
       - 迁入版中移除 `use dm_database_parser_sqllog::{LogParserBuilder, parse_record};`，改用 `use super::*;`（已在 mod tests 顶部，无需重复）。
       - dev-dependencies 中的 encoding crate 在 #[cfg(test)] 内部模块可用，GB18030 测试中的 `use encoding::all::GB18030;` 保持。
       - 迁移完成后删除整个文件：`git rm tests/sqllog_additional.rs`。

    5. **tests/parser_errors.rs**（177 行）：
       - 迁入 src/parser/mod.rs 内部：仅 test_parse_record_timestamp_validation（line 163-176）。在迁入版本中删除其函数体内的 `use dm_database_parser_sqllog::parse_record;`（已通过 `use super::*;` 访问）。
       - 保留在 tests/parser_errors.rs：其余 8 个测试（全部使用 LogParserBuilder + ParseError 公开 API）。
       - 文件顶部 use 不变：`use dm_database_parser_sqllog::{LogParserBuilder, ParseError};`（这两个仍是公开 API）。

    6. **tests/integration_test.rs**、**tests/parser_filters.rs**、**tests/parser_iterator.rs**：完全不动（仅使用公开 API）。

    7. **验证迁移完整性**：
       - tests/ 中不再有任何 `parse_record` 引用：`grep -r 'parse_record' tests/` 应为空。
       - tests/ 中不再有任何 `use dm_database_parser_sqllog::parse_record` 或 `use dm_database_parser_sqllog::{... parse_record ...}` 残留。
       - src/parser/mod.rs 的 #[cfg(test)] mod tests 块包含所有迁入的测试用例（约 35-40 个新增 #[test] 函数 + 任务 1 的 7 个 is_timestamp_start 测试 + LogParserBuilder 编码探测测试）。

    8. **运行 cargo test 全量验证**：
       - `cargo build --tests` 必须通过（tests/ 中无未解析的 parse_record 引用）。
       - `cargo test` 必须全量通过（所有迁入测试在新位置仍然通过，所有保留测试不受影响）。
       - 测试数量：迁入前后 #[test] 总数应基本相等（允许略微差异，因为内部 #[cfg(test)] 现在可访问私有函数，可能合并某些重复用例；但严禁删除任何断言）。

    禁止：不删除任何测试用例（只能迁移位置）；不修改任何测试断言；不动 examples/；不动 src/lib.rs、src/filter/、src/async_api/、src/record.rs、src/error.rs。
  </action>
  <verify>
    <automated>cd /Users/guang/Projects/dm-database-parser-sqllog && [ "$(grep -r 'parse_record' tests/ | wc -l | tr -d ' ')" = "0" ] && ! test -e tests/performance_metrics.rs && ! test -e tests/sqllog_additional.rs && cargo build --tests 2>&1 | tail -3 && cargo test 2>&1 | tail -3</automated>
  </verify>
  <acceptance_criteria>
    - `grep -r 'parse_record' tests/` 输出为空（tests/ 中无 parse_record 引用）
    - `grep -r 'use dm_database_parser_sqllog::parse_record' tests/` 输出为空
    - tests/performance_metrics.rs 不存在（被 git rm）
    - tests/sqllog_additional.rs 不存在（被 git rm）
    - tests/parser_coverage.rs 存在且仅含 2 个 #[test]：iterator_skips_leading_blank_line、crlf_in_multiline_first_line（用 `grep -c '#\[test\]' tests/parser_coverage.rs` 返回 2）
    - tests/edge_cases.rs 存在且仅含 1 个 #[test]：probable_record_start_line_and_iterator_singleline_detection（`grep -c '#\[test\]' tests/edge_cases.rs` 返回 1）
    - tests/parser_errors.rs 存在且 #[test] 数量为 8（原 9 减去 test_parse_record_timestamp_validation）
    - tests/integration_test.rs、tests/parser_filters.rs、tests/parser_iterator.rs 完全未被修改：`git diff tests/integration_test.rs tests/parser_filters.rs tests/parser_iterator.rs` 无输出
    - src/parser/mod.rs 的 #[cfg(test)] mod tests 块内有迁入的关键测试函数（至少包含 `performance_metrics_full`、`parse_record_single_line_no_newline`、`body_without_indicators`、`test_parse_record_timestamp_validation`）：`grep -cE 'fn (performance_metrics_full|parse_record_single_line_no_newline|body_without_indicators|test_parse_record_timestamp_validation)' src/parser/mod.rs` 返回 4
    - `cargo build --tests` 退出码 0
    - `cargo test` 全量通过（退出码 0）
    - cargo test 输出中显示通过的测试数量 ≥ 迁移前的测试数量（不丢失任何用例）
  </acceptance_criteria>
  <done>
    所有直接调用 parse_record 的测试已迁入 src/parser/mod.rs 内部测试模块；仅使用公开 API 的测试保留在 tests/；cargo test 全量通过；tests/ 中无残留 parse_record 引用。
  </done>
</task>

</tasks>

<verification>
端到端验证：

1. `ls src/` 显示：error.rs lib.rs record.rs filter/ async_api/ parser/（无 parser.rs 单文件）
2. `ls src/parser/` 显示：mod.rs builder.rs iterator.rs encoding.rs
3. `cargo check` 退出码 0
4. `cargo build --tests` 退出码 0
5. `cargo build --examples` 退出码 0（验证 examples/filter_slow_queries.rs 仍能调用 LogIterator::filter_by_exec_time，因其保持 pub）
6. `cargo test` 全量通过
7. `grep -r 'parse_record' tests/` 输出为空
8. `grep -c 'crate::filter::adapter\|adapter::filter_by_' src/parser/iterator.rs` 返回 ≥ 2（验证委托调用）
9. is_timestamp_start 私有：`cargo doc --no-deps && grep -r 'is_timestamp_start' target/doc/dm_database_parser_sqllog/` 应无匹配（不在公开 doc 中）
</verification>

<success_criteria>
- REFACTOR-01 完成：src/parser/ 子模块容纳 LogParser、LogParserBuilder、LogIterator、FileEncodingHint、parse_record（私有）、parse_record_with_hint（私有）
- REFACTOR-02 完成：src/filter/ 子模块容纳 filter_by_exec_time / filter_by_sql_contains 泛型函数（pub(crate)），LogIterator 委托调用
- REFACTOR-05 完成：is_timestamp_start、make_invalid_format_error、LO_MASK 等字节级工具私有化，不出现在公开 doc 中
- cargo test 全量通过；cargo build --examples 通过
- 测试迁移无丢失：所有原本依赖 parse_record 的 ~35 个测试用例已迁入 src/parser/mod.rs 内部测试模块
</success_criteria>

<output>
完成后创建 .planning/phases/10-restructure/10-02-SUMMARY.md，记录：
- 各子文件最终行数
- 迁入的测试用例清单（按来源文件分组）
- LogIterator::filter_by_* 可见性修订决议（保持 pub，由 RESEARCH Pitfall 5 推荐）
- cargo test 实际通过的测试数量
- 下一计划（10-03）的衔接点：lib.rs 最终重组、examples/ 验证、覆盖率与 clippy 验收
</output>
</content>
</invoke>