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
promote: when the canonical copy is gone or excluded, a by-name or --toc run silently makes a stale copy canonical and reverts the pool #24
Follow-up from the review of #14. Line numbers are at #14's head as it merges.
What happens
resolve_sources judges whether a copy is stale only while the entry's recorded canonical series is eligible in the run (tools/promote:719). When the canonical copy is gone upstream, or its series is excluded from the run, nothing is judged. A by-name run (promote SLUG) or --toc of the series holding the stale copy then anchors on that copy and makes it canonical. The pool goes back to the earlier version and loses the canonical copy's later edits. The run exits 0 with an ordinary promoted line and no warning.
The refresh refuses the same entry, naming the removal, so the two modes disagree. The by-name run also hides what happened. The rewritten entry no longer records the removed series, so the drift-check goes clean, and its canonical-removed issue closes itself. That issue is the one asking for a decision about whether the lecture was retired, renamed or moved.
Reproduction (with the tools/tests harness)
repo=make_repo(["advanced", "dp-test"])
forseriesin ("advanced", "dp-test"):
repo.lecture(series, "amss", lecture_text("AMSS"))
assertrepo.promote("amss").returncode==0# sources: advanced, dp-testrepo.lecture("advanced", "amss", lecture_text("AMSS", "A fix upstream."))
repo.move_pin("advanced")
assertrepo.promote("--refresh").returncode==0# dp-test kept as a stale sourceassert"A fix upstream."inrepo.pool("amss.md").read_text()
(repo.root/"mirror"/"advanced"/"lectures"/"amss.md").unlink()
repo.move_pin("advanced", 3) # advanced removes (or renames) amss.mdassert"[canonical-removed] lectures/amss.md"inrepo.drift_check().stdoutassertrepo.promote("--refresh").returncode==1# the refresh refuses, naming the removalres=repo.promote("amss") # a by-name (or --toc dp-test) runassertres.returncode==0and"WARN"notinres.stdoutassertrepo.entry("amss")["canonical"] =="dp-test"assert"A fix upstream."notinrepo.pool("amss.md").read_text() # the pool lost the fixassertrepo.drift_check().returncode==0# and the drift-check goes quiet
The same happens to promote amss --exclude advanced while advanced still holds its copy.
When it bites
Only on a manual run after a canonical copy has been removed or renamed upstream. CI's refresh refuses the entry, so the run has to be by name or by toc: a whole-estate promotion, the --toc dp re-homing at QuantEcon/project-monorepo#24, or an operator re-promoting a lecture. The renames in QuantEcon/project-monorepo#76 are the first realistic trigger. Main behaves the same way.
Suggested fix
When the entry's recorded canonical series no longer holds the lecture (or is excluded from the run), and the run would anchor on a recorded source still at an earlier digest, refuse the entry. The refusal should say so and point at the canonical-removed decision, unless sync/canonical.yml names that series. Take care not to refuse a source that is the same lecture only after normalisation: one test is whether promoting it would change the pool file at all. A test like the one above, inverted, covers it.
Activity