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
The admin shows "this translation is out of date", and strategy: "skip_existing" then refuses to re-translate that very field — the two features answer the same question differently.
What happens
Translate de. Provenance stores a fingerprint of the source's translatable content.
Staleness is computed by isRecordStale (src/core/domain/provenance/staleness.ts), and its only consumers are the staleness HTTP routes that feed the admin indicator. The pipeline never asks.
So "already translated" means "not empty" — with no notion of current, and no notion of reviewed: a machine translation nobody read, a placeholder, or a half-typed word all count as done.
Why the obvious fix is wrong
Making SkipExistingStrategy call isRecordStale looks like a few lines. It is a trap, because the two work at different granularities:
Staleness is per document-locale.computeSourceFingerprint(doc, schema) is one sha256 over the whole document's translatable content, and TranslationProvenanceRecord stores one sourceFingerprint per (collectionSlug, documentId, targetLocale).
The strategy decides per field.
So the only thing that integration can express is a document-wide switch: if the document is stale, re-translate every non-empty field. That destroys work:
A document has title and body. A reviewer corrects the German title. Somebody then edits the English body. The document is now stale, so the run re-translates the title too — overwriting a correction whose source never changed.
That is the same failure as #116, reached from a different direction and firing on every run rather than only on publish.
What a correct fix needs
Per-field provenance, so the strategy can ask "did this leaf's source change":
compute a fingerprint per translatable leaf — cheap, the content projector already walks them;
store them — this changes the provenance collection's shape and needs a migration;
give StrategyContext a third input (the source value this leaf was translated from) — a contract change in core;
a strategy or mode that uses it, plus tests.
A cheaper option worth considering instead
Leave skip_existing alone and add a separate, explicitly chosen strategy — "re-translate what is stale" — that re-translates everything when the document is stale. Coarse, and it has the same overwrite behaviour as above, but the editor picks it knowingly rather than being surprised by it. Much smaller, and it removes the contradiction between the indicator and the strategy without a storage migration.
Summary in one line
The admin shows "this translation is out of date", and
strategy: "skip_existing"then refuses to re-translate that very field — the two features answer the same question differently.What happens
de. Provenance stores a fingerprint of the source's translatable content.strategy: "skip_existing", which is the natural choice for "refresh what needs refreshing".Nothing is re-translated. The endpoint returns
200.Why
skip_existinghas exactly one criterion — is the target field empty:Staleness is computed by
isRecordStale(src/core/domain/provenance/staleness.ts), and its only consumers are the staleness HTTP routes that feed the admin indicator. The pipeline never asks.So "already translated" means "not empty" — with no notion of current, and no notion of reviewed: a machine translation nobody read, a placeholder, or a half-typed word all count as done.
Why the obvious fix is wrong
Making
SkipExistingStrategycallisRecordStalelooks like a few lines. It is a trap, because the two work at different granularities:computeSourceFingerprint(doc, schema)is one sha256 over the whole document's translatable content, andTranslationProvenanceRecordstores onesourceFingerprintper(collectionSlug, documentId, targetLocale).So the only thing that integration can express is a document-wide switch: if the document is stale, re-translate every non-empty field. That destroys work:
That is the same failure as #116, reached from a different direction and firing on every run rather than only on publish.
What a correct fix needs
Per-field provenance, so the strategy can ask "did this leaf's source change":
StrategyContexta third input (the source value this leaf was translated from) — a contract change incore;A cheaper option worth considering instead
Leave
skip_existingalone and add a separate, explicitly chosen strategy — "re-translate what is stale" — that re-translates everything when the document is stale. Coarse, and it has the same overwrite behaviour as above, but the editor picks it knowingly rather than being surprised by it. Much smaller, and it removes the contradiction between the indicator and the strategy without a storage migration.Notes