Files
mdpolish/research-wiki/reference/review-projection-schema-v1.md
T

8.1 KiB
Raw Blame History

ReviewDocument 机器投影 schema 1.0

本文记录 mdpolish.review.review_document_to_dict()render_json_report() 当前稳定的跨进程查询口径。公共 Python 类型和 运行校验以 src/mdpolish/review.py 与测试为准;设计理由和批准边界见 0012-review-document-machine-projection.md

1. Schema 身份与入口

每个投影都包含:

{
  "schema_name": "mdpolish.review",
  "schema_version": "1.0"
}

schema 版本独立于 mdpolish 包版本和 modifier 版本。公共入口是:

from mdpolish.review import render_json_report, review_document_to_dict

payload = review_document_to_dict(review, detail="summary")
json_text = render_json_report(review, detail="full")

两者只接受内存中的 ReviewDocument。JSON reporter 编码同 detail 的正式 dict,不定义另一套字段,也不读写文件。

2. 顶层字段

字段 JSON 类型 口径
schema_name string 固定为 mdpolish.review
schema_version string 当前固定为 1.0
detail string summarychangesfull
status string successfailedunstable
current_kind string success_outputpartial_output
stages_complete boolean 是否能证明全部 modifier transform 阶段完成
hash_contract object 所有 Markdown 哈希的算法、编码和规范化口径
coordinate_contract object span、行列和物理换行口径
input object 输入文本摘要;full 增加正文
current object 当前文本摘要;full 增加正文
counts object modifier、完成阶段、实际修改、错误和残留候选数量
modifiers array 全部 modifier 的权威顺序
stages array 已完成 transform 阶段的权威顺序
errors array Pipeline 记录的错误顺序
residual_proposals array 只在 changes / full 出现;候选未应用

JSON object 成员顺序不构成语义。所有 array 顺序构成语义,消费者不得重新按 ID、哈希或文本排序后再解释位置。

3. 内容暴露等级

内容 summary changes full
状态、哈希、位置口径和计数
modifier id、版本和位置
modifier 参数和 applicability
阶段前后哈希、长度和修改数
实际修改的 reason、位置、before / after
稳定错误代码和错误位置
Python 诊断类型和错误消息
残留候选的 reason、expected_text / replacement
输入、当前和阶段完整 Markdown

默认是 summary。被隐藏的内容键不存在;null 和空字符串都不是“已隐藏”的替代值。summary 不含直接正文,但仍含 modifier identity、哈希和计数,不自动等于匿名、脱敏或适合公开传播。

4. 固定口径

4.1 哈希

"hash_contract": {
  "algorithm": "sha256",
  "encoding": "utf-8",
  "normalization": "none"
}

哈希是精确 Markdown 的 sha256(markdown.encode("utf-8")).hexdigest()。不规范化 Unicode、BOM、空白、末尾换行或 CR/LF/CRLF。Change.before_sha256 / after_sha256 是完整阶段快照哈希,不是修改片段哈希。

4.2 坐标

"coordinate_contract": {
  "offset_unit": "unicode_code_point",
  "span_index_base": 0,
  "span_end": "exclusive",
  "location_index_base": 1,
  "physical_line_endings": ["lf", "crlf", "cr"]
}
  • span 相对于所属 ReviewStage.before_markdown,使用 0-based Unicode code point 半开范围;
  • location.line / column 指向 span.start,使用同一阶段修改前文本中的 1-based Unicode code point 位置;
  • CRLF 形成一个物理换行,但在 offset 中占两个 code point
  • 不提供最终全文坐标、UTF-16、byte offset 或终端显示宽度。

所有整数都在 0..2**53-1;参数中的有符号整数在 -(2**53-1)..2**53-1。所有 float 必须有限。

5. 嵌套对象

5.1 文本摘要

inputcurrent 以及 stage 的 before / after 都至少包含:

{
  "sha256": "64 位小写十六进制",
  "code_point_length": 123
}

full 增加 markdowncurrent.markdown 是否为正式输出必须看根字段 current_kindpartial_output 不能当作成功结果。

5.2 Counts

"counts": {
  "modifier_count": 3,
  "completed_stage_count": 2,
  "change_count": 5,
  "error_count": 1,
  "residual_proposal_count": 0
}

change_count 只统计已完成 stage 中的实际 ReviewChange,不含 residual proposal edit。零修改的完整 stage 仍计入 completed_stage_count

5.3 Modifier

所有 detail

{
  "position": 0,
  "modifier_id": "example.normalize",
  "version": "1.0.0"
}

changes / full 增加 parametersapplicabilityparameters 是有序 array-of-pairs;所有内部 tuple 继续投影成 array,不根据二元组外形猜成 JSON object

"parameters": [
  ["pattern", " {2,}"],
  ["replacement", " "]
]

5.4 Stage

所有 detail

{
  "modifier_position": 0,
  "before": {"sha256": "...", "code_point_length": 20},
  "after": {"sha256": "...", "code_point_length": 18},
  "change_count": 1
}

changes / full 增加 changes arrayfull 还给两个文本摘要增加 markdownmodifier_position 引用根 modifiers[position],不复制 modifier 元数据。

5.5 实际 Change

只在 changes / full 出现:

{
  "proposal_index": 0,
  "edit_index": 0,
  "reason": "修改原因",
  "location": {"line": 3, "column": 7},
  "span": {"start": 24, "end": 31},
  "before": "原片段",
  "after": "新片段",
  "before_sha256": "修改前完整阶段哈希",
  "after_sha256": "修改后完整阶段哈希"
}

5.6 Error

所有 detail 都含 codestage、modifier 位置与身份。changes / full 再增加诊断用的 diagnostic_typemessage

stage 稳定 code
preflight run.preflight_failed
transform run.transform_failed
final_review run.final_review_failed

代码只稳定表达失败阶段。diagnostic_type 是 Python 异常类名,message 是人类消息,不能作为稳定程序分支条件。当前 RunError 没有保存更细的稳定原因;不能从类名或消息猜造更细代码。

5.7 Residual proposal

只在 changes / full 出现:

{
  "modifier_position": 0,
  "proposal_index": 0,
  "snapshot_sha256": "当前完整快照哈希",
  "reason": "候选原因",
  "edits": [
    {
      "edit_index": 0,
      "span": {"start": 10, "end": 15},
      "expected_text": "原片段",
      "replacement": "候选片段"
    }
  ]
}

它是 final review 证据,没有应用,不进入 stage 或实际 change count。

6. JSON 编码

render_json_report() 固定使用标准库 JSON 的以下语义:

  • ensure_ascii=False
  • allow_nan=False
  • indent=2
  • 无 UTF-8 BOM
  • 返回字符串末尾不额外添加换行。

返回值是 Python str。调用方保存或发送时负责 UTF-8 编码、媒体类型、权限和保留周期。库不接收路径或文件对象。

7. 兼容策略

schema_version 使用 MAJOR.MINOR

  • 删除、改名、改类型、改变位置/哈希/顺序语义、改变已有 enum 或错误代码含义,需要提升 major;
  • 在相同 detail 中新增更高敏感度的正文承载字段,需要提升 major,或增加必须显式请求的新 detail;
  • 不改变旧字段解释的非正文可选字段,可以提升 minor;
  • 实现修正为重新符合已有契约,不改变 schema 版本;
  • schema 版本不跟随 Python 包版本自动变化。

同一 major 的消费者必须忽略未知 object 字段,但必须保持 array 顺序;不得把未知状态当成 success。消费者应拒绝自己不 支持的 schema major。

schema 1.0 是单向生产契约。当前没有官方反序列化器、JSON Schema 文件、历史迁移器或数据库 schema。