You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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 (#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:
output comes from syncChunkedHashes, which rebuilds the file as:
const{ frontmatter, body }=parseFrontmatterAndBody(targetContent);constbodyText=body.endsWith("\n") ? body : `${body}\n`;constraw=`${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: 6a4aa99 ("Sync translation hash metadata for ja/zh/ko docs.", Sync ja/zh/ko translation hash metadata #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:
constraw=`${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.
Summary
pnpm translate:sync-hashnever 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(#1357), where the tool claimed drift on a page whose English source had not changed in seven months.Reproduction
On a clean
main:But the hashes are already right. Computing them with the repo's own functions:
Running it for real produces this and nothing else, in all three languages:
Run it three times, get three blank lines. It is unbounded.
Repo-wide on clean
main:Cause
syncOneFileonly reports "unchanged" when both the hash and the full re-serialized text match:outputcomes fromsyncChunkedHashes, which rebuilds the file as:parseFrontmatterAndBodymatches/^(---\n[\s\S]*?\n---)\n?([\s\S]*)$/and returnsfrontmatterwith a trailing\nalready appended, then consumes one more\ninto the separator.rawthen adds its own\nback on top of abodythat still begins with the remaining newlines. Round-tripping a file therefore gains one\nevery time,output !== targetContentforever, and theunchangedbranch 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-runis 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.pnpm translate:sync-hashrun dirties 71 files with a whitespace-only diff.Suggested fix
Make the round-trip idempotent, in
syncChunkedHashes:and have
parseFrontmatterAndBodyown the single separating newline, or normalise the leading blank run ofbodybefore reassembly. Then theoutput === targetContentguard starts working and--dry-runbecomes meaningful again. Worth a test that assertssync(sync(x)) === sync(x)..github/scripts/i18n/sync-hash-i18n.tsand.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.
translationSourceHashis 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.