You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
drift-check: a normalised-equal source copy is reported as drift when it moves in lockstep with the canonical copy #15
Since #14, tools/promote treats two same-name copies as one lecture when they are identical after each copy's asset references are normalised to their pool paths (normalised_text). Such a copy is recorded as a source with its own, different digest. tools/drift-check still compares a non-canonical source byte-for-byte: when the source's digest has changed it checks cur == can_bytes and otherwise raises a divergeddrift finding, whose detail text says the copy "was byte-identical at promotion".
Reproduction (with the tools/tests harness)
repo=make_repo(["intro", "intermediate"])
forsin ("intro", "intermediate"):
repo.mirror_file(s, "_static/lecture_specific/short_path/graph.png", b"png")
repo.lecture("intro", "short_path", lecture_text("Shortest Paths", refs=["/_static/lecture_specific/short_path/graph.png"]))
repo.lecture("intermediate", "short_path", lecture_text("Shortest Paths", refs=["_static/lecture_specific/short_path/graph.png"]))
assertrepo.promote("short_path").returncode==0assertrepo.drift_check().returncode==0# the same upstream edit lands in both series, path spelling still differsrepo.lecture("intro", "short_path", lecture_text("Shortest Paths", "edited", refs=["/_static/lecture_specific/short_path/graph.png"]))
repo.lecture("intermediate", "short_path", lecture_text("Shortest Paths", "edited", refs=["_static/lecture_specific/short_path/graph.png"]))
res=repo.drift_check()
Output:
[diverged] lectures/short_path.md: the intermediate copy lectures/short_path.md no longer matches its canonical home in intro
[canonical-moved] lectures/short_path.md: canonical copy in intro changed upstream
The diverged finding opens a drift issue that is false; it clears once the refresh PR merges and re-records the digests. So this is noise, not data loss.
Exposure today
None: every source in the committed ledger is byte-identical to its canonical copy, because promote only admitted byte-identical sources before #14. The first candidates are short_path and ifp_egm once jax is dropped from PROMOTE_EXCLUDE, and any intro/intermediate pair that differs only in /_static/ versus _static/ spelling.
Suggested fix
Give drift-check the same comparison promote uses: before calling a moved source copy diverged, compare its normalised text with the normalised canonical text (promote's normalised_text logic, which only needs the mirror and the slug). A moved copy that is normalised-equal should count as converged/unchanged, and the diverged detail text should stop claiming byte identity at promotion. Alternatively, record in the ledger which sources were admitted by normalisation, so drift-check can tell the two cases apart without re-parsing.
#17, now part of #14, settles the lockstep case described here, so this issue closes when #14 lands. The review found one related case that #17 does not reach: a source that is equal to the canonical copy only after normalisation, catches up in its own asset-path spelling, and then falls behind again. That case is filed as #18, together with a copy that caught up to a canonical version that was never recorded.
Activity
mmcky commentedon Oct 8, 2026
#17, now part of #14, settles the lockstep case described here, so this issue closes when #14 lands. The review found one related case that #17 does not reach: a source that is equal to the canonical copy only after normalisation, catches up in its own asset-path spelling, and then falls behind again. That case is filed as #18, together with a copy that caught up to a canonical version that was never recorded.
drift-check: judge a non-canonical copy by promotion's own rule (#17)