Skip to content

resync regenerates from the source PR's merge-time snapshot — stale content reverts newer target edits #276

Description

@mmcky

Observed 2026-08-18 on lecture-python-programming: commenting \translate-resync on PR #595 (merged 2026-08-12) regenerated sync PRs whose translated sections were built from #595's merge-time snapshot of the source, not from current source main. Anything the source changed in those sections after #595 — in this case the test_pwt.csv repoint from lecture-python-programming#612 (merged earlier the same day) — gets reverted in the regenerated target content.

Concrete evidence, from the regenerated PRs before any merge: lecture-python-programming.zh-cn#93's only lecture-content change was reverting two already-repointed polars.md reads back to the old own-repo raw URL (a URL scheduled for deletion), and lecture-python-programming.fa#154 carries the same two reversions plus a rewrite of three pandas_panel.md data reads from the github.com/QuantEcon/data-lectures/raw/main/… form to the raw.githubusercontent.com/… form — i.e. whatever URL form the snapshot happened to hold. The French regeneration (fr#34) was clean only because that target had not yet received the newer edits, so its sections still matched the snapshot.

The trap is sharpest exactly when resync is most needed: a queued sync PR conflicts because later source changes touched the same lectures, someone resyncs to regenerate it, and the regeneration quietly re-applies the pre-conflict content the rebase refused to. The failure is silent — the PR looks like a normal retranslation and merges cleanly.

Suggested direction: in resync mode, rebase the source diff onto current source main before translating (or diff old-source-at-PR against current main rather than against the PR's own head), so a regenerated section can never carry source content older than what main serves. A cheaper guard: after generating, diff the code cells (not prose) of the regenerated sections against current source main and fail the run if any code cell differs — code cells are language-invariant, so any mismatch is stale-snapshot content by construction.

The state files regenerated in these PRs share the problem: they record hashes against the stale snapshot, so merging one also corrupts the baseline the next sync diffs against.


Fallout ledger (2026-08-19, measured)

Triage: labeled bug + high-priority; W1 (#259) carries a deterministic detection box for this; the regeneration repair stays here. Operating rule until it lands: do not use \translate-resync. Superseded 2026-08-20 — see the ruling comment below. The blanket moratorium is replaced by a measured precondition: \translate-resync is permitted only when git rev-list --count <mergeSha>..origin/main -- <path> is 0 for every file in the source PR (not just the file named in a failure issue). The documented recovery route also moves off resync onto the CLI (translate forward -f / init -f), which reads source off the local filesystem and cannot exhibit this defect.

Method: for all 21 state files across the three targets (7 lectures × 3), the recorded source-sha was compared against the source repo's true last-touch commit for that lecture, plus content probes for each #595/#612 edit (the PyTorch casing fix, the DiscreteRV seed docstring, qe.Timer mentions, and the data-read URL forms). Reference commits on source main: d35eb831 = the #595 batch (last touch for about_py, autodiff, numpy, pandas_panel, python_by_example), 55c87c9f = the #612 repoint (last touch for pandas, polars).

target state vs source content verdict
zh-cn all 7 match seed docstring localized ✓ · pandas_panel raw.githubusercontent form ✓ · polars/pandas URLs ✓ Fully consistent, nothing outstanding. The original batch PR (#89 there) merged at 03:11 before the repoint; the stale regeneration (#93) was correctly closed unmerged.
fr 6 of 7 match; numpy records a2b929f1 (2026-05-13) vs actual d35eb831 numpy is missing both #595 edits: docstring still the pre-#595 text, 2 of 3 qe.Timer mentions numpy.md never received #595. The original batch PR (#30) was closed unmerged and the regeneration (#34) silently omitted the file. State is honest — it flags numpy as pending.
fa pandas and polars record d35eb831 vs actual 55c87c9f — the regeneration overwrote the repoint sync's correct state; about_py records 3213613a (2026-05-09, pre-dates this incident) lectures current except pandas_panel: three data reads carry github.com/QuantEcon/data-lectures/raw/main/… while source at its own last touch uses raw.githubusercontent.com/QuantEcon/data-lectures/main/… Two stale state files (effect: isSourceChanged over-reports — the fail-safe direction) plus a three-line pandas_panel divergence introduced by the #155 restore, which restored a URL form the source itself had moved off. fa about_py is effectively current in content (PyTorch ×3 already correct); its ordinary pending-state heals on the next organic touch.

Corrections to this issue's original account, from the measurement: (1) the pandas_panel rewrite in fa#154 was correct sync content, not snapshot damage — the #595 batch itself moved the source's URL form to raw.githubusercontent, and the hand-restore then overcorrected it; (2) state files record a per-file source-sha (a commit id), not content hashes, and the stale values sit on the fail-safe side — tools over-report staleness rather than mask it; (3) the incident has a second mechanism, distinct from the stale snapshot: a regeneration can silently drop a file of the PR it replaces (fr numpy), which feeds W1's declared-vs-delivered assertion directly.

Repairs — merged and verified 2026-08-19 (both deterministic, no re-translation). The fallout is fully remediated; what stays open here is the bug itself.

Post-merge, the recorded-vs-actual mismatch set across all 21 state files is zero, modulo fa about_py's benign pre-incident pending-state, which self-heals on the next organic touch. Still open on this issue: the regeneration repair. Re-specified 2026-08-20: compare the source snapshot against current source main — English against English, one repos.compareCommits call over the PR's file set — and fail closed on drift, rather than comparing the regenerated target's code cells against source (which is dominated by legitimate localisation divergence). Note a naive move to current main re-opens the inverse defect that #44 repaired; a correct fix splits the pair, base at merge_commit^ and head at main.

Design note for the W1 guard, measured on numpy.md: code cells are not wholly language-invariant — fa and zh-cn localize docstrings and comments inside code cells; fr keeps them English. The invariance check must strip comment/docstring lines or key off the per-language code-comments rule.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghigh-priorityAddress soon

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions