# 函数式修改核心如何工作 ## 1. 它解决什么问题 项目规则如果直接返回一整篇新 Markdown,库无法确认它改了哪里,也无法在文本已经变化时阻止旧位置继续执行。 `mdpolish` 把三个职责分开:项目规则提出修改,库验证并在内存中执行,调用项目决定是否写回文件。 当前机制来自已批准的 [`0008-generic-functional-library-boundary.md`](../design/0008-generic-functional-library-boundary.md)。公共类名、字段和 函数签名以 [`src/mdpolish/`](../../src/mdpolish/) 和测试为准,本文只解释不变量与边界。 ## 2. 当前数据流 ```text 项目选择 Modifier、参数和顺序 │ ▼ 当前 Markdown 快照 │ ▼ Modifier 提出精确修改 ──► 整批验证 ──► 内存中整批应用 ──► 新快照 │ │ └────────── 按项目给定顺序重复 ◄──────────┘ │ ▼ 最终只复查,不再应用 │ ┌────────────────┼────────────────┐ ▼ ▼ ▼ success unstable failed ``` | 层次 | 负责 | 不负责 | | --- | --- | --- | | 不可变数据模型 | 保存快照、范围、候选修改、实际改动、错误和结果 | 项目业务判断 | | `Modifier` | 冻结身份、版本、参数、适用边界和提议函数 | 直接改变字符串或文件 | | 修改执行器 | 校验并原子应用一个修改器批次 | 判断规则是否符合某个项目 | | `Pipeline` | 按显式顺序运行修改器并做最终稳定性复查 | 自动选规则、文件读写和默认组合 | `mdpolish` 不导入使用项目。项目可以使用正则工厂、通用内置修改器,也可以用普通函数建立自己的 `Modifier`。 ## 3. 修改器拥有什么权限 修改函数接收不可变 `DocumentSnapshot`,返回一个 `ProposedChange` 元组。每项候选修改说明原因,并包含一条或多条 精确 `TextEdit`。修改器拥有规则判断权,可以提议插入、删除或替换,但不能通过公共契约原地改变快照,也不能用 整篇新文本绕过执行器。 `Modifier` 还保存稳定 ID、语义版本、冻结后的参数和适用边界。普通函数无需继承基类。相同输入、身份、版本和参数 应产生相同顺序的候选修改;修改函数不得读取文件、网络、环境变量、当前时间或随机数。 Python 不能沙箱隔离任意调用方函数。外部函数若私下写文件,属于绕过库契约的副作用,不在 `mdpolish` 的验证、 审计和回滚保证内。 ## 4. 为什么修改必须绑定快照 每个快照都带有完整 Markdown 的 SHA-256。候选修改及其中每条编辑必须绑定这个哈希,并提供半开字符串范围、该范围 应有的原文和替换文本。执行器再次确认: 1. 哈希对应当前快照; 2. 范围没有越界; 3. 当前位置与预期原文完全一致; 4. 编辑不是无变化操作; 5. 当前修改器批次没有重复或冲突范围。 任意检查失败,当前修改器的整批候选都不执行。范围使用 Python 字符串索引,不是 UTF-8 字节位置;核心不会隐式 改变换行、Unicode 形式或末尾换行。 执行器从文本后方向前应用编辑,避免前面的修改使后面的下标失效;审计记录仍按原文位置排列。 ## 5. `Pipeline` 的状态 `Pipeline` 先预检全部修改器及重复 ID,再按调用方顺序各运行一次。后一个修改器读取前一个修改器生成的新快照。 全部执行完成后,每个修改器对最终快照再提议一次,但复查阶段只验证,不应用,也不会自动开始第二轮。 | 状态 | 含义 | 文本字段 | | --- | --- | --- | | `success` | 运行和复查均完成,所选修改器不再提出修改 | `output_markdown` | | `unstable` | 运行无错误,但最终快照仍有有效候选修改 | `partial_markdown` | | `failed` | 提议、契约或执行验证发生错误 | `partial_markdown` | `success` 只说明调用方选择的这组修改器在这次输入上已经稳定,不说明文档不存在其他质量问题。库只返回内存结果; 调用项目检查状态后,自己决定是否保存。 ## 6. 当前通用能力与边界 除了核心,发布包只提供: - `regex_replace()`:把非空正则匹配转换为精确编辑; - `mapped_line_join()`:按调用方映射合并跨行片段,库不附带词表; - `html_table_entity_unescape()`:在严格表格单元格文本中解除一层受支持的实体转义; - `html_table_layout()`:把严格单行 HTML 表格展开为每行一个表格行。 HTML 能力使用失败关闭的词法子集,不是完整 HTML parser,也不识别 Markdown 围栏。正则工厂只保证定位和执行契约, 不保证调用方正则的业务语义正确。 当前没有默认流水线、文件适配器、CLI、profile、配置加载、批处理、artifact、评审器或项目规则集。安装或导入库不会 自动修改任何文本。实际安装、示例和当前检查命令只以根目录 [`README.md`](../../README.md) 为准。