# Implementation Plan: Deterministic translation from approved memory

## Approach

A new script, not an extension of an existing one. Everything in `.l10n-sync/` today
reads and reports; this is the first thing that writes translated content, and mixing a
writer into a gate would make the gates unsafe to run casually.

The method is the one used by hand for the 134-row table fix, which worked and is worth
keeping: extract the distinct segments needing translation, resolve each exactly once
against the approved memory, apply the resulting map mechanically, and abort on anything
unmapped. Translating by position rather than by distinct segment was what produced
duplicated effort and inconsistent renderings on earlier passes.

Reuses rather than restates: `resolveMemory` from `tm-lookup.mjs` for last-wins
resolution over an append-only memory, `structuralKind` and `segmentsFromLine` from
`harvest-tm.mjs` for the segment model, `splitSections` for alignment, and
`loadKeepInSource` for the segments that are legitimately identical. A sixth copy of the
segment model would be the thing that finally lets the TM and the writer disagree.

Abort is the default, not an error path. A segment with no exact match and no
keep-in-source entry stops the run and names the segment. The alternative — emitting the
source text — is the exact defect spec 006 exists to catch, and it would be absurd to
build a writer that manufactures the thing the verifier hunts.

Structure is copied, never regenerated. Lines are rebuilt from the source line with
only their translatable segments substituted, so markup, identifiers, code spans and
number formats survive because they were never touched.

Fragment links are repaired after reassembly, once the translated headings exist and
their slugs can be computed.

The manifest is regenerated only when content was written, which is FR-006 and the trap
worth guarding: regenerating it without translating is what silently marks stale
Portuguese as current.

## Rollback

The writer touches only files under the locale mirror and writes nothing on abort.
Reverting the commit restores the previous translations; no source content is involved.

## Appendix

### Alternatives considered

**Fuzzy matching below exact equality.** Deferred in the spec and not revisited here.
Exact matching has to be shown to work and be measured before approximate matching is
given authority to write.

**Translating line by line rather than by distinct segment.** Rejected. The corpus has
heavy repetition — 69 distinct cells covered 178 rows in the table fix — so per-position
translation repeats work and lets the same English acquire two renderings.

**Writing through `qc-structure.mjs` so verification is automatic.** Rejected. A gate
that can modify the tree cannot be run safely to ask a question.