Flatten the consumer-keyed tree into the published layout#10
Merged
Conversation
Moves the data out of lecture-python-intro/{static,dynamic}/ into lectures/,
the flat published root, and lifts scripts/ to the repo root, outside the
published tree. This is PLAN Phase 2.
The layout is flat because the URL is the interface: lectures/<filename> maps
to data.quantecon.org/lectures/<filename>. A consumer-keyed folder would imply
a series owns a file, which is false — any lecture may consume any dataset —
and would bake an owner into every URL.
Doing this now is deliberate. Zero lectures reference this repo (verified by
org-wide code search, not just the audit), so every move here is free. Once the
first repoint merges, published filenames become an API and each move is a
breaking change. AGENTS.md now says so where the old note promised the freedom.
Three files with no consumer anywhere were dropped rather than promoted into
the canonical namespace: the two World Bank CSVs (zero org-wide references,
re-downloadable at will, licence never established) and fig_3.ods (confirmed a
pure format twin of fig_3.xlsx — identical sheet, identical 34x6 frame). All
remain in git history.
Also sketches the per-dataset manifest schema (manifest-schema.yml) and
repoints business_cycle.py at lectures/, which would otherwise write to a
directory that no longer exists.
Part of #8
See QuantEcon/meta#336
Part of QuantEcon/workspace-lectures#14
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Implements PLAN Phase 2 by flattening the legacy consumer-keyed layout under lecture-python-intro/ into a flat published tree at lectures/, while moving builder scripts to a non-published scripts/ directory at the repo root. It also documents the new layout and introduces a strawman per-dataset manifest schema to support upcoming metadata/integrity phases.
Changes:
- Flatten/move datasets into
lectures/and remove the legacylecture-python-intro/{static,dynamic,scripts}/READMEs and orphaned World Bank metadata CSV. - Repoint the
business_cycle.pybuilder to write outputs intolectures/and document builders underscripts/. - Update repo docs (
README.md,PLAN.md,AGENTS.md) and addmanifest-schema.ymlto describe/standardize the new published layout and manifest approach.
Reviewed changes
Copilot reviewed 10 out of 23 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/README.md | New documentation for dataset builders living outside the published tree. |
| scripts/business_cycle.py | Updates output directory from legacy dynamic path to lectures/. |
| README.md | Documents the new flat layout and clarifies what is published vs not. |
| PLAN.md | Records Phase 2 completion details and updates roadmap language accordingly. |
| manifest-schema.yml | Adds a strawman manifest schema and sidecar placement convention. |
| lectures/nom_balances.npy | Moves dataset into the flat published lectures/ namespace. |
| lectures/fig_3.xlsx | Moves dataset into the flat published lectures/ namespace. |
| lectures/chapter_3.xlsx | Moves dataset into the flat published lectures/ namespace. |
| lectures/caron.npy | Moves dataset into the flat published lectures/ namespace. |
| lectures/business_cycle_metadata.md | Publishes World Bank metadata dump alongside the dataset for provenance/license capture. |
| lectures/business_cycle_info.md | Publishes series info dump alongside the dataset. |
| lectures/business_cycle_data.csv | Publishes the dynamic snapshot CSV under the new published root. |
| lecture-python-intro/static/README.md | Removes legacy consumer-keyed static README (layout is no longer consumer-keyed). |
| lecture-python-intro/static/Metadata_Country_API_NY.GDP.PCAP.CD_DS2_en_csv_v2_4770417.csv | Drops an orphan/no-consumer file rather than promoting it into the published namespace. |
| lecture-python-intro/scripts/README.md | Removes legacy consumer-keyed scripts README (scripts moved to repo root). |
| lecture-python-intro/dynamic/README.md | Removes legacy consumer-keyed dynamic README (dynamic output now lives in lectures/). |
| AGENTS.md | Updates repo map and documents the “published filenames are an API” constraint post-repoint. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This was referenced Jul 15, 2026
mmcky
added a commit
that referenced
this pull request
Jul 16, 2026
Two small doc corrections surfaced reviewing the pilot: - AGENTS.md's manifest field list was written for the #10 schema sketch and never gained the fields P1 added: license.verified, the integrity migration/upstream split, schema.known_nulls, and builder_status. Bring it current and point to manifest-schema.yml as the authoritative field reference so the two stop drifting. - manifest-schema.yml: note that row_count_floor is the exact row count for a frozen historical extract by design (P1 lingcod = 82), so it is not later "relaxed" as if it were a mistake; a loose floor is for files that grow. See QuantEcon/meta#338 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mmcky
added a commit
that referenced
this pull request
Jul 16, 2026
* P1 pilot: add lingcod_msy_recovery.csv with its manifest The first dataset to land in the published tree, and the first manifest written against the schema sketch. Consumed by lecture-python-intro's msy_fishery lecture, which currently reads it from a relative path — so the downloaded notebook cannot resolve it. The repoint is the paired lecture PR. Licence established before adding, per AGENTS.md: RAM Legacy is CC BY 4.0, attribution-only, so rehosting this extract is permitted. Worth recording how that was found — ramlegacy.org states no licence at all; the authority is the Zenodo record behind its DOI (license id "cc-by-4.0", access_right "open"). Meeting a real file changed the schema in three ways, all folded back into manifest-schema.yml: - integrity splits into `migration` and `upstream`. Lingcod is a byte-perfect copy of what the lecture consumes, yet its upstream provenance cannot be re-derived at all. One "verified" field would have to overstate or understate it; two fields tell the truth. - `builder_status` records `unrecovered`. This file is constructed but ships no builder — the bug AGENTS.md names. The tempting fix is to relabel it verbatim, which buries the gap; instead it is now visible in the catalog. - `known_nulls` declares nulls that are correct. F/Fmsy is null in the terminal assessment year, which a blanket no-nulls validation rule would wrongly reject. Part of QuantEcon/meta#338 See QuantEcon/meta#336 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Codify the two inherited-file manifest states (P1 decisions) The P1 lingcod manifest declares `retrieved: null` and `class: constructed` with `builder: null` / `builder_status: unrecovered`. Copilot flagged both as out of compliance with AGENTS.md — correctly, because the rules had no wording for inherited files. Rather than patch the manifest to dodge the rules (which would mean inventing a retrieval date or misclassifying a constructed file as verbatim), bless both states explicitly so the gap stays visible in the generated catalog and the rules and the manifest stop contradicting. - AGENTS.md: add "Two inherited-file states" under the manifest rules — `retrieved: null` permitted for inherited-undated bytes (paired with an integrity.upstream reason; never reconstructed from git history), and `builder_status: unrecovered` for inherited constructed files (Phase 9), inherited-only so a new constructed file still must ship its builder. - manifest-schema.yml: document the `retrieved` null policy and scope `unrecovered` to inherited files at the two field sites. Provisional P1 decisions, to be folded into the convention. See QuantEcon/meta#338 and QuantEcon/QuantEcon.manual#108. * Tidy manifest docs after the P1 pilot Two small doc corrections surfaced reviewing the pilot: - AGENTS.md's manifest field list was written for the #10 schema sketch and never gained the fields P1 added: license.verified, the integrity migration/upstream split, schema.known_nulls, and builder_status. Bring it current and point to manifest-schema.yml as the authoritative field reference so the two stop drifting. - manifest-schema.yml: note that row_count_floor is the exact row count for a frozen historical extract by design (P1 lingcod = 82), so it is not later "relaxed" as if it were a mistake; a loose floor is for files that grow. See QuantEcon/meta#338 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Reframe licensing as cache-not-host, and metadata as capture-when-available Two tone corrections to the manifest convention, from review discussion — the fields are unchanged, only the surrounding policy language: - Reframe the repo's identity as a stability CACHE for lecture data (snapshots upstream sources so a build doesn't depend on a live API or third-party host), not a content-distribution host. The licence question follows: "is this source OK to cache and serve publicly, with attribution?", not "may we republish it as our own?". Attribution (the manifest `source` block) is the primary obligation; redistribution becomes a cheap binary gate (permitted | restricted) that is a fast yes for public data sources and blocks only genuinely restricted ones (e.g. FRED third-party series). Softens "promoted public host" / "blocker". - State the capture-when-available principle explicitly: rich provenance is always welcome and worth recording when the source provides it, but a missing field is recorded as a reasoned gap, never a bar to landing a useful dataset. Effort scales with the source — a clean one gets a short manifest. Does not touch the integrity method/upstream field structure — that simplification is still under discussion. See QuantEcon/meta#338 and QuantEcon/QuantEcon.manual#108 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Simplify integrity to one axis: upstream + sha256, note not method Applies the simplification agreed in review discussion. The P1 finding stands — migration and upstream are independent questions with different answers — but only one of them belongs in the manifest: - Drop the `migration` sub-block. Migration safety is a ONE-TIME check that matters at the repoint and never again, so it lives in the repoint PR as a Phase 8 gate rather than as a permanent manifest field. The manifest keeps `sha256`, which makes the check reproducible at any later date. Lingcod's verified migration (byte-compare against intro's copy, 2026-07-16) is preserved as a comment pointing at data-lectures#12 / lecture-python-intro#792. - Replace free-text `method` with an optional one-line `note`, populated only when status is not a clean verified — the valuable prose was always the REASON (why lingcod is unverifiable), not a re-typed procedure. - Move the generic how-to-verify-by-class recipe to AGENTS.md, stated once, instead of being repeated in every manifest. - Add `against`: what a verified check compared to (URL, DOI, or repo path), so "verified" is auditable rather than a bare assertion. Net effect: a clean verbatim file now carries a three-line integrity block with zero prose; only genuinely messy provenance earns a note. See QuantEcon/meta#338 and QuantEcon/QuantEcon.manual#108 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Bring PLAN.md in step with the P1 schema decisions AGENTS.md's own rule: when a decision settles, update PLAN.md in the same PR that acts on it. This PR revised the manifest schema in ways four PLAN passages still described in their pre-pilot form: - "Where we're going": the manifest field list predated the pilot — point to manifest-schema.yml as authoritative and name the fields P1 added (integrity, builder_status, known_nulls, license.verified). - Phase 5: link both the invariant-tests bullet and the business_cycle.py retrofit to #14, which carries the builder template and the schema decisions the tests will force (column patterns, known_nulls semantics, dtype vocabulary). - Phase 6: the licence check is per SOURCE, not per file — a cheap binary cache-and-serve-with-attribution gate, per the cache-not-host reframe. RAM Legacy (P1) joins World Bank as the second source already established. - Phase 7: the byte-compare is recorded in the repoint PR as a one-time gate (not a manifest field); verification results land in integrity.upstream as sha256/status/against/date, replacing the retired "method" field; and unverifiable-with-note is the honest known status. - Open-decisions table: licensing strawman restated in cache-not-host terms. See QuantEcon/meta#338 and QuantEcon/QuantEcon.manual#108 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
mmcky
added a commit
to QuantEcon/lecture-python-intro
that referenced
this pull request
Jul 17, 2026
Repoints msy_fishery at the canonical copy in QuantEcon/data-lectures and drops the local one, which nothing else reads. This also fixes the lecture rather than merely relocating its data. The read was a relative path, 'datasets/lingcod_msy_recovery.csv', which only resolves inside a repo checkout — a downloaded notebook has no datasets/ directory, so the cell raised FileNotFoundError in Colab. Reading over https is what makes the notebook self-contained. Uses the interim URL form github.com/QuantEcon/data-lectures/raw/main/… and the data_url convention already used by long_run_growth and inflation_history. Blocked until the data is on data-lectures main (QuantEcon/data-lectures#10, then #11) — until then this URL 404s. The branch URL resolves today, but pointing at a non-default ref is exactly the bug meta#337 is cleaning up in mle.md, so it is not a shortcut worth taking. Verified by running the cell against the data over https: 82 rows, figure renders, terminal-year null in F/Fmsy handled. Output is unchanged — the migrated file is byte-identical (sha256 fc2f873f…) to the copy removed here. Part of QuantEcon/meta#338 See QuantEcon/meta#336 Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PLAN Phase 2. Moves the data out of
lecture-python-intro/{static,dynamic}/intolectures/— the flat published root — and liftsscripts/to the repo root, outside the published tree.Why flat, and why now
The layout is flat because the URL is the interface:
lectures/<filename>maps todata.quantecon.org/lectures/<filename>. A consumer-keyed folder implies a series owns a file, which is false — any lecture may consume any dataset — and would bake an owner into every URL.Doing it now is the whole point. Zero lectures reference this repo, so every move is free. I verified that independently rather than relying on the audit — an org-wide code search for
QuantEcon/data/raw,raw.githubusercontent.com/QuantEcon/dataand the old static paths returns 0 hits; the only references todata-lecturesanywhere are this repo's own docs. Once the first repoint merges (Phase 8), published filenames become an API and every move is a breaking change.AGENTS.mdnow says exactly that, where it previously promised the freedom.Layout decisions (PLAN Phase 2's open question)
lectures/— flat, all 9 datasetsscripts/— buildersmanifest-schema.yml— the schema sketchManifests are the one exception: they live inside
lectures/as sidecars named<filename>.yml, so a dataset can't be moved or removed without its metadata and CI can assert the pairing with a glob. Naming uses the full filename (mpd2020.xlsx.yml, notmpd2020.yml) because a stem-keyed sidecar collides the moment one dataset ships in two formats — precisely thefig_3.xlsx/fig_3.odscase this repo already contained. All strawman until the pilot tests it.Three files dropped rather than promoted
Rather than carry files with no consumer into the canonical namespace (each would then need a manifest, licence check and integrity verification under Phases 6–7):
GDP_per_capita_world_bank.csvandMetadata_Country_API_NY.GDP.PCAP.CD_DS2_en_csv_v2_4770417.csv— an org-wide code search returns zero references to either, they are freely re-downloadable from the World Bank, and their licence was never established.fig_3.ods— verified to carry no provenance the published.xlsxlacks: both parse to a singleSheet1, identical 34×6 shape,DataFrame.equals→True. A pure format twin.All three remain in git history if ever wanted. Happy to keep any of them if you'd rather — this is the Phase 6 keep-or-drop call made explicit.
Reviewing this — read the layout, not the schema
Two things worth knowing before you spend time here.
manifest-schema.ymlis a strawman, and #12 already revises it by ~46 lines. It is labelled provisional in its own header ("every field here is provisional until proven by a real migration") and that is exactly what happened: the pilot in #12 met one real dataset and the schema neededintegritysplit intomigration/upstream, abuilder_statusfield, andknown_nulls. So feedback on the schema's fields is better spent on #12, which carries the tested version. What is worth reviewing here is the layout decision — flat tree, sidecar manifests, full-filename naming — because that is what everything downstream inherits.There is no CI in this repo (no
.github/— that is PLAN Phase 5). "MERGEABLE" here means "no conflicts", not "verified". The verification is the manual work described below.Verification
Ringit status -M), so history follows them.business_cycle.pywrote to../dynamic, which no longer exists — repointed atlectures/and confirmed its path logic resolves to the real directory for all three of its outputs. A restructure that moved the data but left the builder writing into the void would have failed silently at the next refresh.Also here
manifest-schema.ymlsketches the per-dataset manifest. It is worked against a real example rather than a hypothetical one:business_cycle_metadata.mdalready records the World Bank series as CC BY-4.0 with source and periodicity, which proves those fields are actually obtainable and gives Phase 6 its model.Part of #8
See QuantEcon/meta#336
Part of QuantEcon/workspace-lectures#14