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
Commit 8a04862
Browse filesBrowse the repository at this point in the historyBrowse files
* Add the generated data-audit dashboard: scanner, tracker, 3-page site
scripts/build_audit.py scans the 8 synced Python-family lecture repos on
origin/main (clone + grep — never gh search code, which cannot find URLs),
classifies every data reference into the hosting-pattern taxonomy, and
renders a 3-page static dashboard (overview / migration tracker / full
audit) via scripts/render_audit.py.
Three sources of truth, reconciled on every build:
- lectures/*.yml manifests — the migrated datasets
- migration.yml (new) — the migration lifecycle + PR provenance, kept
separate from the manifests so it can be archived when the migration
programme completes without touching the permanent dataset records
- scripts/audit_annotations.yml (new) — curated judgment (descriptions,
provenance classes, live-API pedagogy) for not-yet-migrated references
The strict scan fails on an unannotated data reference or a migration.yml
status that disagrees with what the lectures actually read, so the
dashboard cannot silently rot — the failure mode that killed the
hand-built 2026-07-15 audit artifact within two days.
Part of #20; taxonomy and design system carried over from that artifact.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Deploy the dashboard and the published tree to GitHub Pages
.github/workflows/audit-dashboard.yml builds the dashboard from shallow
clones of the 8 lecture repos and deploys the default Pages site:
dashboard at /, the published lectures/ tree at /lectures/, audit.json
alongside for reuse. Triggers: push to main, weekly cron, manual
dispatch; on PRs touching the audit inputs it runs the strict build as
a guardrail without deploying.
Serving lectures/ on Pages pre-stages PLAN Phase 4: when the
data.quantecon.org DNS question is resolved, only the custom domain
changes. Checkout uses lfs: true so LFS-tracked files publish as bytes,
never pointers.
Part of #20.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Docs: record the dashboard, its update rules, and P2 completion
README gains the audit-dashboard section; AGENTS.md gains the
keep-it-truthful rules (migration.yml updated in the same PR as a
landing/repoint; annotations for new references; never commit site/ or
audit.json) and the expanded repo map; PLAN.md checks off the Pages
deploy (default domain — custom domain stays open), adds the Phase 5
workflow entry, and marks pilot P2 complete (#17,
QuantEcon/lecture-python-programming#578, QuantEcon/lecture-python.myst#973).
Part of #20.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Address Copilot review: taxonomy gap, status validation, notebook guard
- render_audit.py: add the external-web pattern to PATTERN_META so a
non-GitHub data URL would surface in the hosting-pattern table and
distribution chart instead of being silently omitted (no current ref
triggers it; the failure mode was the point)
- build_audit.py: validate migration.yml status values in the scan-stage
consistency check (an unknown status fails --strict with a clear
message); render_audit.py's stepper raises a named error as backstop
- build_audit.py: flag any .ipynb under lectures/ outside _static/ as an
unscanned_notebooks problem. Every lecture source today is MyST .md and
the only notebooks are builder/figure helpers (deliberately not
consumers); if a notebook-format lecture ever appears, the build now
refuses to miss it silently
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: AGENTS.md
+16-1Lines changed: 16 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -78,6 +78,16 @@ For the public data sources most snapshots come from (World Bank, FRED, Eurostat
78
78
79
79
One exception: a `restricted` file the lectures have already served publicly may be cached here if it is marked `redistribution: restricted` with a `note` and logged for licence review in the migration-licensing tracker ([workspace-lectures#20](https://github.com/QuantEcon/workspace-lectures/issues/20)) — resolve it (permission, an open replacement, or removal) before `data.quantecon.org` is promoted as a public open-data host.
80
80
81
+
### The audit dashboard stays truthful
82
+
83
+
The generated dashboard (`scripts/build_audit.py`, [#20](https://github.com/QuantEcon/data-lectures/issues/20)) verifies its three inputs against a fresh scan of the lecture repos, and the strict build **fails** when they drift. Keep them current in the same PR as the change that moves reality:
84
+
85
+
-**Landing or repointing a dataset** → update its `migration.yml` record (status, PR refs, dates). A dataset marked `repointed` whose consumers still read an old URL — or the reverse — is a build failure, by design.
86
+
-**A new manifest** (`lectures/*.yml`) → add its `migration.yml` record; delete any stale entry for the same file in `scripts/audit_annotations.yml` (manifested datasets must not be annotated there).
87
+
-**The weekly scan flags an unannotated reference** (a lecture repo started reading a new file) → classify it and add an entry to `scripts/audit_annotations.yml`; that file holds judgment (description, provenance, why-live), never facts the scan can derive.
88
+
89
+
`site/` and `audit.json` are generated — never commit them; CI rebuilds and deploys on every push to `main`.
90
+
81
91
## Cross-repo hygiene
82
92
83
93
- Changes here often pair with PRs in lecture repos and issues in `QuantEcon/meta`. In commit messages and PR bodies, **never place a GitHub closing keyword (`fixes`, `closes`, `resolves`, …) immediately before a cross-repo reference** like `QuantEcon/meta#336` — GitHub will auto-close the referenced issue when the commit lands on the default branch. Write "See QuantEcon/meta#336" or "Part of QuantEcon/meta#336".
@@ -89,8 +99,13 @@ One exception: a `restricted` file the lectures have already served publicly may
89
99
lectures/ # the published tree — flat, served at data.quantecon.org/lectures/
Copy file name to clipboardExpand all lines: PLAN.md
+3-2Lines changed: 3 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -70,7 +70,7 @@ The sidecar naming uses the **full filename** (`mpd2020.xlsx.yml`, not `mpd2020.
70
70
71
71
### Phase 4 — Publishing
72
72
73
-
-[] GitHub Pages deploy of the published tree, **`lfs: true` at checkout** (else pointer files publish)
73
+
-[x] GitHub Pages deploy of the published tree, **`lfs: true` at checkout** (else pointer files publish) — landed 2026-07-17 with the audit dashboard (`.github/workflows/audit-dashboard.yml`, [#20](https://github.com/QuantEcon/data-lectures/issues/20)): the default `quantecon.github.io/data-lectures/` site serves the dashboard at `/` and the published tree at `/lectures/`. The custom domain below stays open
74
74
-[ ]`data.quantecon.org` DNS + custom domain (an old NestJS box on AWS Sydney currently answers this name — investigate before repointing)
75
75
-[ ] Verify `access-control-allow-origin: *` on served files (pyodide/JupyterLite, meta#143)
@@ -84,6 +84,7 @@ The sidecar naming uses the **full filename** (`mpd2020.xlsx.yml`, not `mpd2020.
84
84
85
85
Full automation:
86
86
87
+
-[x] Audit dashboard workflow ([#20](https://github.com/QuantEcon/data-lectures/issues/20), added 2026-07-17): `.github/workflows/audit-dashboard.yml` rebuilds the full-universe data audit + migration tracker from the 8 lecture repos' `main` (push to main / weekly / dispatch) and deploys it with the published tree to Pages. Strict mode fails the build on an unannotated data reference or a `migration.yml` status the scan contradicts
87
88
-[ ] PR validation: manifest schema check + per-dataset invariant tests (expected columns/dtypes, row-count floor, date-range recency, no all-NaN columns, overlap-window agreement with the previous vintage) on every PR touching data. The schema decisions these tests force — column patterns for wide files, `known_nulls` exact-vs-ceiling, a canonical dtype vocabulary — are researched in [#14](https://github.com/QuantEcon/data-lectures/issues/14)
88
89
-[ ] Retrofit `scripts/business_cycle.py` to the four-stage builder contract — it has fetch/transform/write today but **no validate stage**. Builder architecture and a copy-able template: [#14](https://github.com/QuantEcon/data-lectures/issues/14)
89
90
-[ ] Scheduled refresh workflow for dynamic datasets — cron per cadence class, runs the builder (fetch → pre-process → validate → write), lands the result as a PR whose diff summary (rows added, date-range delta, overlap-window changes) is the review surface; low-risk series may auto-merge on green (first consumer: the UNRATE pilot, meta#338 P4)
@@ -116,7 +117,7 @@ Verify that what this repo holds is actually the data it claims to be — agains
116
117
The first end-to-end deployment: one dataset per hosting pattern, each the hardest representative of its class, carried through the full chain — layout, manifest, integrity check, publish, lecture repoint. Validates the convention empirically before anything is written into a standard. Sequence P1 → P2 → P3 → P4, each a small PR set (data repo + consuming lecture repos).
117
118
118
119
-[x]**P1 — local-path static**: `lingcod_msy_recovery.csv` (`msy_fishery`, intro). Tests: single-PR green build under `-nW`, Colab-unchanged download, catalog metadata for an author-assembled file. **Complete 2026-07-17** — data half #12, repoint QuantEcon/lecture-python-intro#792 (lecture build green in the single repoint PR); served URL verified byte-identical to the manifest `sha256`; Colab holds by construction (the lecture now reads a public URL, where the old relative path was exactly what broke downloaded notebooks); metadata findings recorded in meta#338. **The repo is live from this merge** — the pyodide/CORS check below remains open
119
-
-[]**P2 — cross-series shared static**: the `pandas_panel` trio (`realwage.csv`, `countries.csv`, `employ.csv`), consumed by programming **and** python.myst. Tests: flat namespace with two consuming series, one data PR updating two lecture repos; retires 5 of the 8 legacy-repo references as a side effect
120
+
-[x]**P2 — cross-series shared static**: the `pandas_panel` trio (`realwage.csv`, `countries.csv`, `employ.csv`), consumed by programming **and** python.myst. Tests: flat namespace with two consuming series, one data PR updating two lecture repos; retires 5 of the 8 legacy-repo references as a side effect. **Complete 2026-07-17** — data half #17, repoints QuantEcon/lecture-python-programming#578 and QuantEcon/lecture-python.myst#973; both lecture repos' own stale copies deleted in the repoint PRs. Lifecycle recorded in `migration.yml`
120
121
-[ ]**P3 — external-repo static with LFS**: the `heavy_tails` set (Forbes ×2, cities ×2) plus the SCF pair from `high_dim_data`. Tests: served URL makes the raw-vs-media LFS trap invisible, Pages handles LFS objects (`lfs: true`), builders (`webscrape_forbes.ipynb`, `generating_mini.md`) migrate alongside their data
121
122
-[ ]**P4 — dynamic snapshot twin**: `UNRATE`, consumed today by 4 lectures across 3 repos via 2 access methods. Tests: the full dynamic template — manifest, four-stage builder, refresh-as-PR, canary catching an induced failure — plus the documented live-call ↔ snapshot switch mechanism
122
123
-[ ] Verify each migrated URL with a pyodide/JupyterLite fetch (CORS, meta#143)
Copy file name to clipboardExpand all lines: README.md
+23-1Lines changed: 23 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -41,9 +41,31 @@ See the [draft convention](https://github.com/QuantEcon/QuantEcon.manual/pull/10
41
41
| Path | What | Published |
42
42
| --- | --- | --- |
43
43
|`lectures/`| the published tree — flat. Every dataset lives here, directly. No folder implies ownership by a lecture series: any lecture may consume any file | yes |
44
-
|`scripts/`| builders for constructed and dynamic datasets | no |
44
+
|`scripts/`| builders for constructed and dynamic datasets, plus the audit-dashboard generator| no |
45
45
|`manifest-schema.yml`| the per-dataset manifest schema (strawman — see [`PLAN.md`](PLAN.md) Phase 2) | no |
46
+
|`migration.yml`| the migration lifecycle tracker — which PRs landed and repointed each dataset (transitional; archivable when the migration programme completes) | rendered |
46
47
47
48
The tree is flat because the URL is the interface: `lectures/<filename>` maps to
48
49
`data.quantecon.org/lectures/<filename>`, so a file can never be re-filed under a
49
50
new owner and break its consumers. Anything outside `lectures/` is not served.
51
+
52
+
## The audit dashboard
53
+
54
+
A **generated** dashboard covering all data referenced by the 8 synced
55
+
Python-family lecture repos — the full-universe audit plus a per-dataset
56
+
migration tracker — deploys to this repo's GitHub Pages site alongside the
57
+
published `lectures/` tree ([data-lectures#20](https://github.com/QuantEcon/data-lectures/issues/20)).
58
+
59
+
```
60
+
python scripts/build_audit.py all --strict # scan + render into site/
61
+
```
62
+
63
+
The scan greps each lecture repo's `main` (clones under `--repos-dir`; defaults
64
+
to this repo's parent, matching the workspace-lectures layout), classifies every
65
+
data reference, and reconciles three sources of truth: the manifests
Copy file name to clipboardExpand all lines: scripts/README.md
+9Lines changed: 9 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -14,3 +14,12 @@ bug.
14
14
`business_cycle.py` is run by hand today and has no validate stage; retrofitting
15
15
it to the four-stage contract (fetch → pre-process → validate → write) is
16
16
PLAN Phase 5.
17
+
18
+
## Not builders
19
+
20
+
| Script | What |
21
+
| --- | --- |
22
+
|`build_catalog.py`| generates `CATALOG.md` from the manifests (`lectures/*.yml`) |
23
+
|`build_audit.py`| the audit dashboard: scans the 8 lecture repos, writes `audit.json`, renders `site/`|
24
+
|`render_audit.py`| the render stage of `build_audit.py` (HTML generation) |
25
+
|`audit_annotations.yml`| curated judgment for not-yet-migrated data references — the strict scan fails when a new reference has no entry here and no manifest |
0 commit comments