156 lines
8.8 KiB
Markdown
156 lines
8.8 KiB
Markdown
# 第一版内存清洗核心如何工作
|
|
|
|
## 1. 它解决什么问题
|
|
|
|
清洗组件如果直接返回一整篇新 Markdown,调用方只能看到修改后的结果,很难确认它实际改了哪里。组件保存的
|
|
旧位置还可能在文本变化后误中另一段内容;同一批修改发生重叠时,按不同顺序执行也可能得到不同结果。
|
|
|
|
当前核心把“判断应该改什么”和“安全地执行修改”分开:组件只描述绑定当前文本的精确修改,公共执行器统一
|
|
验证并应用。核心建立时先不引入真实清洗规则、文件读写或 Markdown parser,让组合与审计协议独立可运行;
|
|
现在第一个真实组件已经在这套协议上完成验证,没有改变核心接口。
|
|
|
|
已经实现的范围来自已批准的
|
|
[`0003-first-executable-core-architecture.md`](../design/0003-first-executable-core-architecture.md)。精确类名、字段和
|
|
函数签名以 [`src/mdpolish/`](../../src/mdpolish/) 中的代码和测试为准,本文不维护第二份 API 清单。
|
|
|
|
## 2. 当前数据流
|
|
|
|
```text
|
|
输入 Markdown 字符串
|
|
│
|
|
▼
|
|
带内容哈希的当前快照
|
|
│
|
|
▼
|
|
组件提出精确修改 ──► 整批验证 ──► 整批应用 ──► 新快照
|
|
│ │
|
|
└──────── 按组件顺序重复 ◄──────────────┘
|
|
│
|
|
▼
|
|
最终只重新提议,不再应用
|
|
│
|
|
┌────────────────┼────────────────┐
|
|
▼ ▼ ▼
|
|
success unstable failed
|
|
```
|
|
|
|
核心只有四层:
|
|
|
|
| 层次 | 当前职责 | 明确不负责 |
|
|
| --- | --- | --- |
|
|
| 数据模型 | 保存快照、范围、候选修改、实际改动、错误和结果 | 业务规则和文件路径 |
|
|
| 组件基类 | 声明身份、版本、参数、适用边界并提出修改 | 应用修改和组织流水线 |
|
|
| 修改执行器 | 统一验证并原子应用一个组件批次 | 判断 Markdown 业务语义 |
|
|
| 流水线 | 排列组件、刷新快照、处理失败并做最终复查 | 读取文件、选择项目 profile |
|
|
|
|
依赖保持单向:组件基类和修改执行器只依赖数据模型,流水线可以调用前三者,底层模块不反向调用流水线。
|
|
|
|
## 3. 为什么修改必须绑定快照
|
|
|
|
每个 Markdown 快照都带有根据完整字符串计算的 SHA-256。候选修改和其中每条文本编辑都必须指向这个哈希,
|
|
还要同时提供原文范围和该范围预期出现的文字。
|
|
|
|
执行时会再次检查:
|
|
|
|
1. 哈希仍然对应当前快照;
|
|
2. 范围没有越过字符串边界;
|
|
3. 当前位置的文字与组件声明的预期原文完全一致;
|
|
4. 替换后确实会改变内容。
|
|
|
|
任何一项不满足,当前组件的整个批次都不会执行。这使位置只在其产生时的快照内有效,不允许把旧候选修改悄悄
|
|
套到后来变化的 Markdown 上。
|
|
|
|
范围使用 Python 字符串下标,而不是 UTF-8 字节位置。核心保留输入的换行、Unicode 形式和末尾换行,不做隐式
|
|
规范化。
|
|
|
|
## 4. 组件为什么只提出自动修改
|
|
|
|
第一版组件只返回能够立即、唯一执行的候选修改。遇到不知道正确修法的截断、损坏表格、疑似幻觉或无法读取的
|
|
图片时,组件应忽略,不猜测修复,也不额外生成“仅检查”结果。
|
|
|
|
每个组件必须提供稳定标识、`MAJOR.MINOR.PATCH` 版本、可冻结的参数和非空适用边界。适用边界需要由组件作者说明
|
|
它处理什么结构、依赖哪些严格前置条件、明确排除什么。组件还必须满足确定、无副作用和幂等约束;不能读取文件、
|
|
网络、环境变量、当前时间或随机数。
|
|
|
|
最终复查能发现多个组件组合后仍会继续提出修改,但不能从有限输入证明一个组件对所有文本都幂等。因此,幂等性
|
|
既由最终复查保护当前运行,也必须由组件自己的针对性测试证明其适用范围内的行为。
|
|
|
|
独立检查和人工建议目前没有实现。以后只有出现明确消费者和闭环时,才通过新 design 增加平行接口,不在当前
|
|
组件结果中补可空字段或状态枚举。
|
|
|
|
## 5. 一个组件批次如何保证原子性
|
|
|
|
一个组件可以提出多个候选修改,每个候选修改又可以包含多个文本编辑。执行器先验证该组件本次提出的全部编辑,
|
|
只有整批通过才从后向前应用;任意一条失败,整批保持原样。这里的原子边界是“当前组件本次执行的全部修改”,
|
|
不是单独一条编辑。
|
|
|
|
当前冲突规则有意保守:
|
|
|
|
| 两项编辑的关系 | 结果 |
|
|
| --- | --- |
|
|
| 两个非空范围真正重叠 | 冲突 |
|
|
| 两个非空范围只相邻 | 允许 |
|
|
| 两次插入位于同一点 | 冲突 |
|
|
| 两次插入位于不同点 | 允许 |
|
|
| 插入点位于非空范围内部、起点或终点 | 冲突 |
|
|
|
|
如果业务动作需要替换一段文字并在边界追加内容,组件应把它表达成同一条替换,而不是依赖编辑执行顺序。
|
|
|
|
## 6. 流水线状态代表什么
|
|
|
|
流水线先对所有组件做元数据预检,避免运行到一半才发现重复标识或无效版本。之后每个组件只执行一次,后一个组件
|
|
只能读取前一个组件产生的新快照。清洗阶段出现异常、契约错误或编辑验证错误时会立即停止,且不再进行最终复查。
|
|
|
|
所有组件完成后,流水线让它们针对最终快照重新提出一次修改,但这一阶段只验证、不应用:
|
|
|
|
| 状态 | 含义 | Markdown 字段 |
|
|
| --- | --- | --- |
|
|
| `success` | 清洗和最终复查均完成,所选组件不再提出修改 | 只提供成功输出 |
|
|
| `unstable` | 清洗无错误,但最终复查仍有有效候选修改 | 只提供诊断用部分文本和残留候选 |
|
|
| `failed` | 清洗或最终复查发生错误 | 只提供诊断用部分文本和错误 |
|
|
|
|
最终复查是只读阶段,因此某个组件失败后仍会继续复查其余组件。错误与其他组件的有效残留修改可以同时保留,最终
|
|
状态以 `failed` 为准。流水线不会因为 `unstable` 自动开始第二轮。
|
|
|
|
`success` 只表示本次选中的自动清洗组件已经稳定,不表示文档没有截断、幻觉、表格损坏、图片断链或其他未实现
|
|
规则能够发现的问题。
|
|
|
|
## 7. 审计记录能回答什么
|
|
|
|
每条实际执行的文本编辑都会生成一条改动记录,说明:
|
|
|
|
- 是哪个组件、哪个版本和流水线位置执行的;
|
|
- 属于哪个候选修改,以及在该候选修改中的编辑序号;
|
|
- 组件给出的修改理由;
|
|
- 修改前范围、原文和替换内容;
|
|
- 当前组件批次修改前后的快照哈希。
|
|
|
|
同一候选修改中的多条记录共享候选引用,同一组件批次中的所有记录共享批次前后哈希。记录只描述已经发生的修改;
|
|
验证失败或最终复查中没有执行的候选不会冒充实际改动。
|
|
|
|
这些内容在核心中只存在于内存返回值中。核心外已经有一个获批的本地实验 reporter,可以校验修改链并把审计、
|
|
成功 Markdown 和 diff 保存到私有产物目录;机制见
|
|
[`local-experiment-artifacts.md`](local-experiment-artifacts.md)。这没有改变核心接口,也不允许把失败结果中的部分文本
|
|
写成正式输出或写回原文件。
|
|
|
|
## 8. 当前验证和剩余边界
|
|
|
|
核心测试继续使用短小的假组件,不包含或复制真实文档。它们覆盖空文本、中文和组合 Unicode、插入/删除/替换、
|
|
范围冲突、过期哈希、批次原子性、组件连锁影响、错误阶段、审计关联和成功结果再次运行等行为。首个真实组件另用
|
|
合成样例测试,并在本地真实材料上只读复核;机制与结果见
|
|
[`arxiv-submission-stamp.md`](arxiv-submission-stamp.md)。
|
|
|
|
实际可用的安装与验收命令、最近一次验证日期和结果只在根目录
|
|
[`README.md`](../../README.md#当前可用检查) 维护。
|
|
|
|
当前仍然没有:
|
|
|
|
- 除严格删除 arXiv 提交边栏戳外的其他论文、GovDoc 或 HTML 表格清洗组件;
|
|
- 独立文档检查、人工建议或审核流程;
|
|
- Markdown parser、AST 或共享业务中间表示;
|
|
- 通用文件输入、公共 CLI、通用批处理、项目 profile 格式和生产集成;
|
|
- 审计结果的长期存储、自动清理或脱敏输出协议。
|
|
|
|
当前只有一个固定数据和组件组合的本地实验脚本,不构成上述公共能力。这些边界中的任何一项要进入实现,都需要先用
|
|
新的 design 明确语义、代价和验收方式。
|