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.
scripts/build_audit.pyclassifies a data reference by finding the code that reads it —read_csv,read_excel,np.loadand 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 inlecture-wasm— the same sibling coupling that made repoint rule 1 necessary, in a form the audit cannot see.chapter_3.xlsxinflation_history.md:228{download}chapter_3.xlsxinflation_history.md:220{download}fig_3.xlsxfrench_rev.md:60dette.xlsxfrench_rev.md:61assignat.xlsxfrench_rev.md:62fig_3.xlsxfrench_rev.md:60dette.xlsxfrench_rev.md:61assignat.xlsxfrench_rev.md:62life-expectancy-vs-gdp-per-capita.csvsimple_linear_regression.md:411{download}life-expectancy-vs-gdp-per-capita.csvsimple_linear_regression.md:421{download}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/, thefrench_revlinks use/blob/, and none of them sit near aread_*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 itprose), and they belong in the samerefslist.Two things fall out of doing it that way.
fully_migratedstarts telling the truth, so a dataset with a stale prose link cannot be markedrepointed— 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.