Connected translation without l10nSource never shows source changes: stamp the missing hash once on open #343
Labels
No labels
bug
enhancement
needs-triage
ready-for-agent
ready-for-human
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/deckle#343
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
A connected translation whose elements (or front matter) carry no
l10nSourceis never marked "changed in the default language", however much its source changes afterwards. Opening such a translation in the editor should stamp the missing hashes once — treating the element as translated as of that moment — so that later changes to the source are indicated like everywhere else.Current behavior
Reported on the hosted editor (site
cloonar): the user edits an existing, enabled element of a page in the default language; the default-language tree shows the page's "modified" badge, but the German tree keeps the page's green "translated" dot and the Languages view shows no change. The German translation is connected (l10n: connected) and, as confirmed on the site, its element shortcodes have nol10nSourceparam.The engine's rule:
l10n.ChangedUIDslists only elements whose storedl10nSourcediffers from the source element's current hash; "an element without l10nSource is unknown and never listed".markOutdated(the tree) andtranslationInfo(the page answer'schangedlist, which drives the element cards' "changed" marks) both build on it, andpageops.TranslationPageChangeddoes the same for the page-levell10nSource. Nothing stamps a missing hash:l10n.StampSourceruns only when an element is translated or saved in the translation, and opening the page (openPage, which already repairs the connected invariant and persists the repair) leaves the param absent. Reproduced locally: stripl10nSourcefrom a translated element, change its source body in the default language, andGET /api/tree?lang=destaystranslated; opening the translation does not add the param.Translations end up unstamped when they were written by hand (AGENTS.md "Translations by hand" says to leave the param out), created by
harness lang add(the home page) or any path that is not the editor's translate/save, or imported from an existing site (migrate-site).Desired behavior
Opening a connected translation in the editor (GET /api/page and GET /api/page/elements in a non-default language — the same reads that repair the invariant) stamps every translated element, item and the front matter that has no
l10nSourcewith the current hash of its source, and persists that like the repair. From then on a change to the source is reported exactly as for an element translated in the editor: the page answer'schangedlist, the element cards' marks, the tree's "outdated" state and the Languages view.Edge cases:
l10nnotconnected) is left alone: it carries no hashes by design.l10nSourcekeeps it, even if stale — stamping must never overwrite an existing hash, or it would erase a real "changed" verdict.repair translationone (a stamp is part of holding the translation to the invariant); no new snapshot kind.Decisions
harness checkis not changed to warn on a missing hash — after this change a missing hash is transient and harmless.Key interfaces
l10n.StampSource(source, translated, schemas)stamps one translated element and its items; a new or extended owner is needed for "stamp every element of a translation that lacks a hash, and the page-level hash" — it must reuseHash/ItemHash/PageHash, never re-derive them. The rule "is this element stamped" issourceParamininternal/l10n; keep it the one owner.internal/server(openPage, which callsl10n.Repairand persists) — the natural caller.l10n.PageHash/l10n.StampPageChangesfor the front matter'sl10nSource.scaffold/site/AGENTS.md"Translations" → "Change tracking" ("A missingl10nSourcemeans unknown and shows no mark") and "Translations by hand" ("Never writel10nSource… no changed mark until the element… is next saved") must say instead that the editor stamps a missing hash when the translation is first opened.docs/api.mdGET /api/page "Languages"/"Writes" describe what opening a connected translation repairs and persists; add the stamp there.docs/architecture.md"Multilingual sites" mentions the repair in one sentence; adjust if it states what the open writes. Theedit-contentandmigrate-siteskills point at those AGENTS.md sections and restate nothing, so they only need a re-read for a sentence that contradicts the new behaviour.Acceptance criteria
l10nSourcewrites the current source hash onto that element (nested elements and items included), with the file otherwise unchanged and canonical.l10nSourcegets the page-level hash on open.l10nSourceis never overwritten by the open.changedand the tree reportoutdated; changing the source page's title makespageChangedtrue.l10nSource, source changed afterwards, page opened once → treeoutdated(fails before the change, passes after).internal/element,scaffold,docsandinternal/serverpass.How to verify
go test ./internal/l10n/ ./internal/server/ ./scaffold/ ./docs/ ./internal/element/.harness inita site,harness lang add de, translate a page connected, delete thel10nSourceparams from the.de.mdby hand, open the German page in the editor, change the English element, and watch the German tree row turn "outdated".Assumptions to check
openPageis the only read that persists a repair (docs/api.md lists GET /api/page and GET /api/page/elements) — stamp on every such read, not only one.Out of scope
UntranslatedUIDs); today only the page answer'suntranslatedlist shows it. A separate decision.harness checkorharness migrate.Blocked by
None - can start immediately