Repository navigation
The audit cannot see prose references — 10 {download}/link refs to files the migration will delete #42
Description
scripts/build_audit.py classifies a data reference by finding the code that reads it — read_csv, read_excel, np.load and friends. Lectures also link to the same files in prose, and those references are invisible to the scan. Ten of them exist today, every one pointing at a file the migration is going to delete.
Found while scoping repoint set 2. Not hypothetical: had I repointed the code and deleted intro's copy as in set 1, the strict audit would have gone green while two published lectures carried a 404 download link.
The ten
All point at lecture-python-intro's committed copies, including the ones in lecture-wasm — the same sibling coupling that made repoint rule 1 necessary, in a form the audit cannot see.
| Data file | Where | Kind | Migration set |
|---|---|---|---|
chapter_3.xlsx |
intro inflation_history.md:228 |
{download} |
set 2 |
chapter_3.xlsx |
wasm inflation_history.md:220 |
{download} |
set 2 |
fig_3.xlsx |
intro french_rev.md:60 |
prose link | set 3 |
dette.xlsx |
intro french_rev.md:61 |
prose link | set 3 |
assignat.xlsx |
intro french_rev.md:62 |
prose link | set 3 |
fig_3.xlsx |
wasm french_rev.md:60 |
prose link | set 3 |
dette.xlsx |
wasm french_rev.md:61 |
prose link | set 3 |
assignat.xlsx |
wasm french_rev.md:62 |
prose link | set 3 |
life-expectancy-vs-gdp-per-capita.csv |
intro simple_linear_regression.md:411 |
{download} |
wave 4 |
life-expectancy-vs-gdp-per-capita.csv |
wasm simple_linear_regression.md:421 |
{download} |
wave 4 |
Why this is worse than an undercount
A missing read would show up as a dataset with fewer consumers than it has — visible, and probably noticed. A missing prose link is different in kind: the tracker can record a dataset as fully repointed, the strict build can pass, and a reader can still click a dead link. The guardrail reports success on a broken state, which is the failure mode it exists to prevent.
It also interacts badly with the deletion rule. "Delete the lecture repo's own copy in the repoint PR" is safe when every consumer has moved — and the audit is what tells us they have. If it cannot see prose references, it cannot answer that question, so the rule rests on a check that does not cover it.
Scope, honestly
This is a reader-facing break, not a build break. A dead {download} link does not fail a lecture build, so nothing in either repo's CI catches it either. It surfaces when someone clicks.
Both kinds also use a URL form the scan has no reason to look at: the {download} directives use /raw/, the french_rev links use /blob/, and none of them sit near a read_* call.
Suggested fix
Scan for the file paths, not only the read idioms. Once a dataset is known — every migrated file has a manifest, and every unmigrated one has an annotation — the audit can grep each lecture repo for that filename and flag any occurrence not already accounted for by a classified read. That catches {download}, markdown links, and prose mentions of a path, without inventing a new taxonomy: they are references to a known dataset, in a new hosting pattern (call it prose), and they belong in the same refs list.
Two things fall out of doing it that way. fully_migrated starts telling the truth, so a dataset with a stale prose link cannot be marked repointed — the migration consistency check begins covering the case that motivated it. And the strict build starts failing on exactly the condition that is silently true right now.
A cheaper interim, if the full scan is more than is wanted: a targeted check that no lecture references github.com/QuantEcon/lecture-*/(raw|blob)/main/lectures/(datasets|_static)/… for any file that has a manifest here. Narrower, but it would have caught all ten.
Meanwhile
Each repoint set fixes its own prose references by hand, and the PR says so explicitly. Set 2 (chapter_3.xlsx) does this. Recording the general problem here so the manual step is a known stopgap rather than something rediscovered when a set forgets it.
Part of #8. Related: #20 (the dashboard this scans for), and PLAN "Repoint rules", whose deletion rule depends on this coverage.
Activity
inflation_history: repoint the "hosted on github" link too
inflation_history: repoint the "hosted on github" link too
mmcky commentedon Aug 6, 2026
Correction: the count is 12, not 10 — and the sweep that produced it had the same blind spot it was documenting
Copilot, reviewing QuantEcon/lecture-python-intro#824, flagged a reference this issue's inventory had missed:
A link to the directory, not to a file. The inventory above was built by searching for links ending in a data-file extension — so a directory link has nothing to match, and was invisible to the very sweep written to catch invisible references. Worth stating plainly: the method used to find the audit's blind spot shared it.
The failure mode is also worse than the ones already listed. That directory survives this migration holding other files, so the link keeps returning 200 while quietly pointing somewhere that no longer contains the spreadsheet it introduces. A 404 gets noticed; a link that silently means the wrong thing does not.
The two additional references
lectures/datasets/directoryinflation_history.md:82lectures/datasets/directoryinflation_history.md:71Both now point at
CATALOG.mdinstead: a reader following "hosted on github" gets the dataset registry with source, licence, integrity status and consuming lectures, which is more than the folder gave them, and it is generated so it cannot drift.Two more of the same shape, for a later wave
Re-sweeping properly also found these, which are not data files but are the same class of invisible reference into a directory the migration will touch:
_static/lecture_specific/inequality/data.ipynbinequality.md:618usa-ginibuilderinequality.md:616That one matters beyond a broken link:
usa-gini-nwealth-tincome-lincome.csvis constructed by that notebook, fromSCF_plus_mini. When it migrates, the builder migrates with it, and these links have to follow.What this changes about the fix
It sharpens the argument for scanning by filename against the manifests rather than by URL pattern. Any regex over link syntax will keep missing shapes nobody anticipated — this issue is now its own evidence for that. Matching known dataset paths and directories against every lecture repo does not depend on guessing the form a reference takes.
Two additions to the suggested check: it should cover directory references to a migrated file's former location, not only file references; and it should treat a reference that still resolves as a finding, since a stale-but-200 link is the harder case to catch by any other means.
inflation_history: read longprices.xls and chapter_3.xlsx from data-l…
inflation_history: read longprices.xls and chapter_3.xlsx from data-l…
longprices.xls and chapter_3.xlsx: record the repoint (#43)
mmcky commentedon Aug 7, 2026
Re-swept today: eight of the ten are already fixed, and the inventory is missing a whole repo
Two corrections, in opposite directions. The count of outstanding references is much smaller than the table suggests, and the scope of the inventory is one repo narrower than the problem.
Eight of the ten are done. All six
french_revprose links now point atdata-lectures/blob/main/lectures/…(intro and wasmfrench_rev.md:60-62each), and bothchapter_3.xlsx{download}directives point atdata-lectures/raw/main/lectures/chapter_3.xlsx(introinflation_history.md:228, wasm:220). Both directory links from the correction comment are onCATALOG.md(intro:82, wasm:71). What is left in the workspace repos is four, not ten:life-expectancy-vs-gdp-per-capita.csvsimple_linear_regression.md:411{download},/raw/simple_linear_regression.md:421{download},/raw/_static/lecture_specific/inequality/data.ipynbinequality.md:618/tree/linkinequality.md:616/tree/linkThe inventory is workspace-scoped, and the class is not.
lecture-intro.zh-cncarries seven members of it. Five are already repointed, because the sync workflow copies whole cells and the English fix rode along:french_rev.md:67,68,69(all three spreadsheets, on data-lectures),inflation_history.md:98(theCATALOG.mddirectory link) and:245(thechapter_3.xlsx{download}). Two are unfixed, and they are unfixed for exactly the reason the four above are — their English originals still are:simple_linear_regression.md:421({download}) andinequality.md:610(the/tree/link intolecture-python-intro). So the real remaining set is six across three repos, and fixing the four upstream ones clears the zh-cn pair on the next sync — for.mdsources only, and only for editions that have a sync workflow (lecture-python-programming.mlhas none).That also bites the suggested fix.
build_audit.pysetsSCAN_REPOSto the eight workspace repos and excludes translations "by decision" (:45-57), so a filename-against-manifests scan built there would reproduce this issue's blind spot in a new form: correct method, wrong repo list.The
data.ipynblink is worse than a link. That notebook is excluded from the scan twice over —build_audit.pytakeslectures/**.mdonly and skips/_static/(:215-216,:222-224) — and it readsmedia.githubusercontent.com/media/QuantEcon/high_dim_data/main/SCF_plus/SCF_plus_mini.csvat line 37 in all three repos (intro, wasm, zh-cn), byte-identical. The sync orchestrator is.md-only, so zh-cn's twin can never receive a sync PR for it. That is three hand edits in three repos, and it belongs on the same work item as the twoinequality.mdprose links rather than being tracked separately.Sequencing. None of this gates the
high_dim_datafold. A naming hazard worth flagging: this issue's "set 3" isfrench_rev(done), while step 3 of QuantEcon/workspace-lectures#23 is the six-filehigh_dim_datafold — and step 3 has zero prose exposure. Neither intro nor wasm holds a copy of those six files, every read is a cross-repo URL, and no{download}or prose link names any of them. All six remaining references, plus the threedata.ipynb:37builder reads, land in step 4 (life-expectancy,usa-giniand its builder). Worth stating on the fold's PR so the manual step is not re-litigated there.mmcky commentedon Aug 31, 2026
Closing — re-measured 2026-09-01 against
mainof both repos. Of the six references the 2026-08-07 re-sweep left, the four that named a data file are fixed:simple_linear_regression.md's{download}now points atraw.githubusercontent.com/QuantEcon/data-lectures/main/lectures/life-expectancy-vs-gdp-per-capita.csvin bothlecture-python-intro(line 411) andlecture-wasm(line 421), and intro's own copy is gone (its old raw URL 404s). The two remaining/tree/links (introinequality.md:618, wasm:616) point atlecture-python-intro/…/inequality/data.ipynb, which still exists — it is a builder notebook that was never a migration target, so those links are correct as they stand. The zh-cn pair inherits the{download}fix on its next.mdsync.The structural point stands and is recorded where it belongs: the audit cannot see prose references, and PLAN.md's repoint rules and QuantEcon/workspace-lectures#14 ("One thing no check will catch") both carry it. Nothing further to track here.