Repository navigation
feat(translator): refresh a translation whose source moved, not just an empty one - #168
Merged
SearheiParkhamchuk merged 3 commits intoOct 5, 2026
Conversation
…an empty one A translation receipt recorded one fingerprint for the whole document, so `skip_existing` could only ask "is the target empty". The admin flagged a locale as out of date and a run then changed nothing. The receipt now records one fingerprint per translatable leaf, keyed by the leaf's id-based address, in the same text column as JSON. No schema change and no migration. `skip_existing` refreshes a leaf whose source moved since it was translated, and leaves a sibling nobody edited alone. `overwrite` is unchanged. A leaf is recorded three ways: the hash it was translated from, a marker for one the run saw and declined, or absent when it appeared after the translation. The marker is what stops a partial run writing a shorter map that reads as drift forever. Accepted price: the receipt cannot tell a human's text from the plugin's, so a target somebody rewrote by hand is overwritten once its own source changes. Fingerprinting the target instead would read every leaf as hand-edited after a round-trip through Payload, and refreshes would stop silently. closes #118
The button under the "out of date" badge ran `overwrite`, so it replaced every translated leaf of the locale, including ones a reviewer had corrected and whose source had never moved. It now runs `skip_existing`, which refreshes only the leaves the receipt shows as stale.
…rd type How the plugin decides a locale is out of date is its own business: the hash width, the address grammar and the three-valued leaf record are mechanism, not contract. A consumer reading the sidecar collection wants which document, which locale and when it was translated; whether it is stale is answered by the staleness endpoint. `TranslationProvenanceRecord` therefore no longer carries `sourceFingerprint` or `dismissedFingerprint`, and neither the fingerprint type nor its parser is exported from the package entry. The fingerprints live on an internal `ProvenanceReceipt` that extends the public record. This removes two fields from a published type. Shipping it as a minor while the package is pre-1.0.
SearheiParkhamchuk
requested review from
ChiefCreator and
dogfrogfog
as code owners
October 5, 2026 16:37
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
🎉 This PR is included in version 0.15.0 🎉 The release is available on npm package (@latest dist-tag) Your semantic-release bot 📦🚀 |
|
🎉 This PR is included in version 1.2.0 🎉 The release is available on npm package (@latest dist-tag) Your semantic-release bot 📦🚀 |
|
🎉 This PR is included in version 2.10.1 🎉 The release is available on npm package (@latest dist-tag) Your semantic-release bot 📦🚀 |
|
🎉 This PR is included in version 1.11.2 🎉 The release is available on npm package (@latest dist-tag) Your semantic-release bot 📦🚀 |
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #118
The problem
A translation receipt recorded one fingerprint for the whole document, so
skip_existingcould only ask one question: is the target empty? The admin flagged a locale as out of date, a run was started, and nothing changed.What changes
The receipt now records one fingerprint per translatable leaf, keyed by the leaf's id-based address, stored as JSON in the same
textcolumn. No schema change, no migration.skip_existingrefreshes a leaf whose source moved since it was translated and leaves a sibling nobody edited alone.overwriteis unchanged, and the strategies are not deprecated.A leaf is recorded three ways, and the third state is load-bearing:
Without the marker, a partial run writes a shorter map, which reads as drift forever — and the skipped leaf could only be added by translating it, which the strategy refuses to do.
Addresses come from the source document rather than the walked data, because the reconciler strips a per-locale row's
id. A unit guard now compares both sides' addresses, not just their text.Accepted price
The receipt cannot tell a human's text from the plugin's. A target somebody rewrote by hand is overwritten once its own source changes. Fingerprinting the target instead would read every leaf as hand-edited after a round-trip through Payload, and refreshes would stop silently. This is pinned by a test, not left to chance.
Public API
TranslationProvenanceRecordno longer carriessourceFingerprintordismissedFingerprint. How the plugin decides a locale is out of date is its own business — the hash width, the address grammar and the leaf record are mechanism, not contract. A consumer reading the sidecar wants which document, which locale and when; staleness is answered by the endpoint.This removes two fields from a published type. It ships as a minor while the package is pre-1.0.
The admin button
The button under the "out of date" badge ran
overwrite, so it replaced every translated leaf of the locale, including corrections whose source had never moved. It now runsskip_existing.Verification
Not yet exercised against current
main— the branch is behind it.Not covered
The admin status panel has no automated test of any kind, so the button change above is guarded by review only.