fix(i18n): harden stopped-merge recovery
This commit is contained in:
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-08-08-automatic-translation-pairing-merges.md
|
||||
2026-08-08-automatic-translation-pairing-merges.md: a1b92c97240e2019b188b606dc079b2211a89238
|
||||
2026-08-08-automatic-translation-pairing-merges.zh.md: 5c7249dc436d24aa955d9c042c8d1bdc84655868
|
||||
2026-08-08-automatic-translation-pairing-merges.md: e70864f1227fe11d7895dd85b0a99d166753a685
|
||||
2026-08-08-automatic-translation-pairing-merges.zh.md: 08da67d78e5cca23e3c5c698644c667813697812
|
||||
|
||||
@@ -14,15 +14,15 @@ A bilingual consistency record contains the two owner files' exact blob hashes.
|
||||
|
||||
The driver parses the ancestor, current, and other records and loads the six owner blobs named by their hashes. It independently runs Git's default three-way text merge for the English and Chinese triplets, requires both merges to be clean, verifies language switchers and the pairing structural signature, stores the two merged blobs, and writes their hashes as the canonical record. This composes confirmations already present in both parents; it never records an ordinary one-sided documentation edit.
|
||||
|
||||
The driver fails with an ordinary unresolved sidecar when a record is malformed, an object is missing, an owner uses another merge strategy, either owner has content conflicts, or the merged pair violates structural checks. Add/delete and rename shapes remain manual because their path ownership is not the same three-record operation.
|
||||
The driver fails with an ordinary unresolved sidecar when a record is malformed, an object is missing, an owner uses another merge strategy (including a non-text `merge.default` inherited by an otherwise unspecified path), either owner has content conflicts, or the merged pair violates structural checks. Add/delete and rename shapes remain manual because their path ownership is not the same three-record operation.
|
||||
|
||||
`pnpm run resolve-translation-pairing-conflicts` applies the same algorithm after a merge has already stopped. Before writing any sidecar, it proves that the staged owner blob IDs and working-tree bytes equal its independent merges; then it writes and stages every safe record as one batch while leaving unrelated conflicts untouched.
|
||||
`pnpm run resolve-translation-pairing-conflicts` applies the same algorithm after a merge has already stopped. Before writing any sidecar, it proves that the sidecar still contains Git's untouched conflict result and that the staged owner blob IDs and working-tree bytes equal its independent merges. It writes and stages every safe record as one batch even when another pair still needs manual work, then reports the remaining pairing conflicts and exits unsuccessfully so callers cannot mistake a partial resolution for a completed merge.
|
||||
|
||||
`pre-merge-commit` and `pre-commit` verify staged `.i18n.yaml` files against the exact index bytes of their owners. They validate driver output but do not regenerate records, so bypassing a hook cannot silently bless translation drift; the corpus-wide `doc-sync` check remains authoritative in CI.
|
||||
|
||||
## Verification
|
||||
|
||||
Script tests exercise clean composition through a real custom-driver Git merge, explicit recovery from an unresolved index, owner-content conflicts, record parsing, and worktree-local installation. The existing corpus verifier continues to prove that a committed record matches its two owners.
|
||||
Script tests exercise clean composition through a real custom-driver Git merge, explicit recovery from an unresolved index, mixed safe and owner-conflicted pairs, edited sidecars, non-text default merge configuration, record parsing, and worktree-local installation. The existing corpus verifier continues to prove that a committed record matches its two owners.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
|
||||
@@ -14,15 +14,15 @@ Status: implemented
|
||||
|
||||
驱动会解析祖先、当前和另一侧的记录,并加载其中 hash 指向的六个 Markdown blob。它分别对英文文档的三个 blob 与中文文档的三个 blob 运行 Git 默认的三方文本合并,要求两次合并都干净完成,校验语言切换行与配对结构签名,存储两个合并后的 blob,再将其 hash 写入规范记录。这一过程组合两个父提交中已经存在的确认;它绝不会为普通的单侧文档编辑写入记录。
|
||||
|
||||
记录格式错误、对象缺失、配对文档采用其他合并策略、任一配对文档存在内容冲突,或合并后的配对违反结构检查时,驱动会让伴随文件保持为普通的未解决冲突。新增、删除及重命名情形仍需手工处理,因为它们的路径归属关系无法由上述基于三份记录的操作处理。
|
||||
记录格式错误、对象缺失、配对文档采用其他合并策略(包括原本未单独指定策略的路径继承了非文本 `merge.default`)、任一配对文档存在内容冲突,或合并后的配对违反结构检查时,驱动会让伴随文件保持为普通的未解决冲突。新增、删除及重命名情形仍需手工处理,因为它们的路径归属关系无法由上述基于三份记录的操作处理。
|
||||
|
||||
`pnpm run resolve-translation-pairing-conflicts` 会在合并已经停止后应用同一算法。写入任何伴随文件之前,它会先验证暂存区中配对文档的 blob ID 以及工作树中的文件字节,都与工具独立完成的合并结果一致;随后它会将所有可安全生成的记录作为一个批次写入并暂存,同时不改动无关冲突。
|
||||
`pnpm run resolve-translation-pairing-conflicts` 会在合并已经停止后应用同一算法。写入任何伴随文件之前,它会验证伴随文件仍保留 Git 生成且未经改动的冲突结果,并验证暂存区中配对文档的 blob ID 以及工作树中的文件字节都与工具独立完成的合并结果一致。即使其他配对仍需手工处理,它也会将所有可安全生成的记录作为一个批次写入并暂存;随后报告剩余的配对冲突并以非零状态退出,确保调用方不会把仅部分解决误认为合并已经完成。
|
||||
|
||||
`pre-merge-commit` 与 `pre-commit` 通过限定范围的配对检查,对照两侧文档在索引中的精确字节校验暂存的 `.i18n.yaml` 文件。这些钩子会验证驱动输出,但不会重新生成记录,因此绕过钩子也无法默默确认发生漂移的译文;CI 中全语料的 `doc-sync`(文档同步门禁)仍是权威检查。
|
||||
|
||||
## 验证
|
||||
|
||||
脚本测试通过一次使用真实自定义驱动的 Git 合并来覆盖无冲突组合,并覆盖从含未解决条目的索引中显式恢复、配对文档内容冲突、记录解析和 worktree 本地安装。既有的全语料校验器继续证明已提交的记录与两侧配对文档相符。
|
||||
脚本测试通过一次使用真实自定义驱动的 Git 合并来覆盖无冲突组合,并覆盖从含未解决条目的索引中显式恢复、可安全解决的配对与配对文档冲突的配对并存、被编辑过的伴随文件、非文本默认合并配置、记录解析和 worktree 本地安装。既有的全语料校验器继续证明已提交的记录与两侧配对文档相符。
|
||||
|
||||
## 考虑过的替代方案
|
||||
|
||||
|
||||
Reference in New Issue
Block a user