Summary
maybeGenerateStateFile (src/sync-orchestrator.ts) builds each .translate/state/<file>.yml fresh from its six known fields (source-sha, synced-at, model, mode, section-count, tool-version) and overwrites the file. Any key the engine does not know is silently dropped on the next sync. This is the same class as #246 fixed for the config.yml writers; the state writer needs the same read-merge-write treatment.
Why now
project-translation ruled 2026-08-24 (provenance contract P2, research/2026-08-24-git-for-translation-tracking §7) that editor sign-off will be recorded as a reviewed: {by, role, date, target-sha, source-sha, via} block in the lecture's state file, written by a workflow on approval and audited by textstrata. That record cannot land while the writer discards unknown keys. This issue is the gate; the workflow is edition-side and follows.
Requested behaviour
- On every state-file write path (sync,
forward, init, resync/state-file-only), read the existing file if present, update the engine-owned keys, and preserve every other top-level key verbatim.
- Staleness of a preserved
reviewed: block is not the engine's concern: consumers compare its source-sha / target-sha against the current fields. The engine must not delete it on resync; it may optionally set a lifecycle key (e.g. status: translated) that a later sign-off flips to reviewed, if that is cheaper than the SHA comparison for readers — design call for the implementer.
- Unit test: a state file with an unknown key round-trips through each write path unchanged apart from the engine-owned fields.
- Harness-first: exercise on the
test-translation-sync lanes before release.
Verified
2026-08-24 against main: the writer at sync-orchestrator.ts (maybeGenerateStateFile, ~L713) constructs the object from scratch and writes; there is no read of the existing file. Fields verified at HEAD of intro.zh-cn and programming.zh-cn.
Refs: project-translation#49 (tracker), decision 9 in plans/lifecycle-metrics.md; related class #246.
Summary
maybeGenerateStateFile(src/sync-orchestrator.ts) builds each.translate/state/<file>.ymlfresh from its six known fields (source-sha,synced-at,model,mode,section-count,tool-version) and overwrites the file. Any key the engine does not know is silently dropped on the next sync. This is the same class as #246 fixed for theconfig.ymlwriters; the state writer needs the same read-merge-write treatment.Why now
project-translation ruled 2026-08-24 (provenance contract P2, research/2026-08-24-git-for-translation-tracking §7) that editor sign-off will be recorded as a
reviewed: {by, role, date, target-sha, source-sha, via}block in the lecture's state file, written by a workflow on approval and audited by textstrata. That record cannot land while the writer discards unknown keys. This issue is the gate; the workflow is edition-side and follows.Requested behaviour
forward,init,resync/state-file-only), read the existing file if present, update the engine-owned keys, and preserve every other top-level key verbatim.reviewed:block is not the engine's concern: consumers compare itssource-sha/target-shaagainst the current fields. The engine must not delete it on resync; it may optionally set a lifecycle key (e.g.status: translated) that a later sign-off flips toreviewed, if that is cheaper than the SHA comparison for readers — design call for the implementer.test-translation-synclanes before release.Verified
2026-08-24 against
main: the writer atsync-orchestrator.ts(maybeGenerateStateFile, ~L713) constructs the object from scratch and writes; there is no read of the existing file. Fields verified at HEAD of intro.zh-cn and programming.zh-cn.Refs: project-translation#49 (tracker), decision 9 in
plans/lifecycle-metrics.md; related class #246.