Backfill TWN links for users who predate account linking (T433621 tile 2)

Users who did the translate-interface-messages task under the old click-based flow have no twn_links row — the linking UI shipped with T433428, after they finished — so the essential-work messages scanner has no subject for them and tile 2 reads 0 despite real translations on translatewiki.net. Nothing heals this without them returning to link by hand: the scanner iterates twn_links and nothing else.

The script creates the missing identity rows, with the evidence bar being name match + activity alignment: the same-named translatewiki account must have NS8 translations into exactly that wiki's language at/after the user's first kit contact with the task. An account that exists but never translated into the candidate's language is reported and skipped — the alignment is the attestation, not the name alone.

Two writes per accepted candidate, both idempotent:

  • twn_links via insertTwnLinkIfMissing (ON CONFLICT DO NOTHING — a real link made by the user meanwhile always wins). baseline = the account's CURRENT core count via fetchCountWithTimeout, the live linking flow's own function: milestone crediting starts from now, identical to a fresh link — no historical milestones are invented.
  • The messages scanner's cursor, seeded at the kit ANCHOR (earliest translate_interface_messages event) and only when no state row exists. The scanner's next pass walks their history from first kit contact and writes the tile-2 items itself; the script never fabricates item rows. linked_at deliberately stays NOW (the truth about when this administrative link was made) — the cursor, not linked_at, carries the reach lower bound.

Candidates come from event contact, not completions: the tile counts artifacts, so a user who translated without clicking "Mark as done" qualifies exactly as much as one who clicked.

Verified end-to-end on a DB copy against the live TWN API: 15 candidates found; 2 accepted — Kambai Akau/kcg (id 30080, 11 aligned post-anchor translations) and Soul Train/lez (id 8428, 16 aligned), the second a genuine old-flow user the dry run surfaced unprompted; 13 correctly skipped (staff names with no TWN account, an account with no aligned-language translations, a fabricated control user). Apply wrote 2 links (baselines 500 and 195) + 2 cursors; a second run reports 0. Then the REAL scanner run against the applied copy added 13 items (8 kcg + 5 lez — the core subset of the aligned edits) and tile 2 went 10 -> 23 with headline == drill-down intact.

Prod run (single-writer rule): webservice stop -> git pull -> dry-run -> --apply -> webservice start. No build needed (script-only). Items appear on the scanner's first pass after boot.

Bug: T433621 Co-Authored-By: Claude Fable 5

Merge request reports

Loading