ITADN

translate:sync-hash never converges: reports 71/84 files as drifted and appends a blank line every run

#1358Openchristian-byrne 创建于 15 天前
bug
C
christian-byrnecommented
## Summary `pnpm translate:sync-hash` never converges. It reports 71 of 84 files as needing a hash sync when their hashes are already correct, and every run it appends one more blank line after the frontmatter of each translated file. The two are the same bug. Found while adding a section to `tutorials/image/qwen/qwen-image-layered.mdx` (https://github.com/Comfy-Org/docs/pull/1357), where the tool claimed drift on a page whose English source had not changed in seven months. ## Reproduction On a clean `main`: ``` $ bun .github/scripts/i18n/sync-hash-i18n.ts --dry-run tutorials/image/qwen/qwen-image-layered.mdx [ja] would sync hash: ja/tutorials/image/qwen/qwen-image-layered.mdx [zh] would sync hash: zh/tutorials/image/qwen/qwen-image-layered.mdx [ko] would sync hash: ko/tutorials/image/qwen/qwen-image-layered.mdx Done: 3 updated, 0 already in sync, 0 missing target(s) ``` But the hashes are already right. Computing them with the repo's own functions: ``` computed block hashes: { _intro: "19900234", "Qwen-Image-Layered workflow": "ba937275", "Model links": "98d12555", "FP8 version": "6bffdd17", "Workflow settings": "b0f81aa2" } computed aggregate: bf2f2000 recorded in zh/ja/ko: bf2f2000, same five block hashes ``` Running it for real produces this and nothing else, in all three languages: ``` @@ -13,6 +13,7 @@ translationBlockHashes: --- + import UpdateReminder from '/snippets/ja/tutorials/update-reminder.mdx' ``` Run it three times, get three blank lines. It is unbounded. Repo-wide on clean `main`: ``` $ bun .github/scripts/i18n/sync-hash-i18n.ts --dry-run Done: 71 updated, 13 already in sync, 0 missing target(s) ``` ## Cause `syncOneFile` only reports "unchanged" when both the hash and the full re-serialized text match: ```ts const existingHash = getExistingHash(targetContent); if (existingHash === expectedFileHash && output === targetContent) { return { status: "unchanged", warnings: [] }; } ``` `output` comes from `syncChunkedHashes`, which rebuilds the file as: ```ts const { frontmatter, body } = parseFrontmatterAndBody(targetContent); const bodyText = body.endsWith("\n") ? body : `${body}\n`; const raw = `${frontmatter}\n${bodyText}`; ``` `parseFrontmatterAndBody` matches `/^(---\n[\s\S]*?\n---)\n?([\s\S]*)$/` and returns `frontmatter` with a trailing `\n` already appended, then consumes one more `\n` into the separator. `raw` then adds its own `\n` back on top of a `body` that still begins with the remaining newlines. Round-tripping a file therefore gains one `\n` every time, `output !== targetContent` forever, and the `unchanged` branch is unreachable for chunked files. Because the blank line is inside the body, it does not change any hash, which is why the recorded hashes stay correct while the tool keeps insisting they are not. ## Impact - `--dry-run` is not usable as a drift signal. "71 files need a hash sync" currently means "71 chunked files exist", not "71 files drifted". A genuine drift is indistinguishable from the noise. - Every `pnpm translate:sync-hash` run dirties 71 files with a whitespace-only diff. - It is already in the history: 6a4aa997 ("Sync translation hash metadata for ja/zh/ko docs.", https://github.com/Comfy-Org/docs/pull/1228) added exactly this blank line to the qwen page along with the intended frontmatter change. ## Suggested fix Make the round-trip idempotent, in `syncChunkedHashes`: ```ts const raw = `${frontmatter}${bodyText}`; ``` and have `parseFrontmatterAndBody` own the single separating newline, or normalise the leading blank run of `body` before reassembly. Then the `output === targetContent` guard starts working and `--dry-run` becomes meaningful again. Worth a test that asserts `sync(sync(x)) === sync(x)`. `.github/scripts/i18n/sync-hash-i18n.ts` and `.github/scripts/i18n/chunked-translate.ts`. ## Note on a claim this disproves It looked at first as though the zh/ja/ko mirrors were drifting because they carry an English-derived fingerprint. They are not. `translationSourceHash` is documented as "SHA-256 of its English source", so carrying the English hash is correct by design, and for this page the recorded value is exactly the value the current English source produces. The drift is in the tool's own reporting, not in the data.
1 条评论