# `mix phoenix_kit_ecommerce.backfill_translation_fingerprints`
[🔗](https://github.com/BeamLabEU/phoenix_kit_ecommerce/blob/0.5.11/lib/phoenix_kit_ecommerce/mix_tasks/phoenix_kit_ecommerce.backfill_translation_fingerprints.ex#L1)

ONE-SHOT backfill (design §4.1, owner's decision 2026-09-03): stamps the
CURRENT source text as the reference fingerprint for every existing shop
translation. Every product/category that already has a translation for a
language moves to `:fresh` the moment this runs, so the staleness sweep
(design §4.3) starts from an empty queue instead of re-translating the
entire catalog on its first tick — 634 resources (627 products + 7
categories, per the design doc's §2 measurement) is the concrete number
this was written against.

Deliberately blunt: it does not check whether a stored translation is
ACTUALLY faithful to its source — it declares "whatever is live today is
the reference," which is the accepted cost (design §4.1: "если
какой-то из существующих переводов уже разошёлся с источником, это
расхождение замораживается"). **Never run this a second time against a
catalog that has been live under the sweep** — it would re-freeze any
drift the sweep had since correctly caught as `:stale`, silently
un-flagging it. It IS safe to re-run against a catalog that has
acquired brand-new translations no reference exists for yet (a fresh
import, a manual translation done outside this pipeline) — for those,
stamping a reference is exactly the intended, idempotent behavior.

A field with no source, or no translation, is left alone — nothing to
stamp; per design §4.1 it still resolves as `:missing` or has no state
at all, never `:stale`.

## Usage

    mix phoenix_kit_ecommerce.backfill_translation_fingerprints
    mix phoenix_kit_ecommerce.backfill_translation_fingerprints --dry-run
    mix phoenix_kit_ecommerce.backfill_translation_fingerprints --source-lang en-US --languages de-DE,fr-FR

## Options

  * `--dry-run` — report how many rows per table WOULD be touched,
    without writing.
  * `--source-lang` — defaults to
    `PhoenixKitEcommerce.Translations.default_language/0`.
  * `--languages` — comma-separated target languages; defaults to
    every enabled language except the source (mirrors design §4.6's
    default for the `shop_translation_languages` setting).

## Safety

This task touches ONLY the `metadata` column (the
`_translation_fingerprints` key within it) — it never writes
translated content, slugs, or any other field. Each table gets exactly
one `UPDATE`, matching the cost design §2 measured for a full-catalog
hash pass (tens of milliseconds, not a per-row loop). Run it against
the shared stand only as the project's own separate, explicitly
announced live-verification step (see the project's worktree
instructions) — never as a byproduct of running this package's tests,
and never against the dev database from a throwaway checkout.

# `backfill`

```elixir
@spec backfill(Ecto.Repo.t(), String.t(), [String.t()], keyword()) :: [
  {String.t(), non_neg_integer()}
]
```

The backfill itself, factored out of `run/1` so it can be exercised
directly against a test database without going through
`Mix.Task.run("app.start")`. One `UPDATE` (or, with `dry_run: true`,
one `SELECT count(*)`) per table — see the moduledoc for exactly what
it touches. Returns `[{table_name, affected_row_count}]`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
