data: BLS OEWS and CES series ingest for PFS-relevant occupations and health-care employment #695
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Spec docs/superpowers/specs/2026-09-09-code-family-longitudinal-design.md (§P50).
Ingest BLS OEWS (occupation × area wages: 29-1xxx physicians/NPs/PAs, 29-2xxx health technologists, 31-9xxx medical assistants and other clinical support — the
actorelement's "clinical staff") and CES (health-care employment, ambulatory settings) intobls.oews/bls.ceswith the BLS series ids kept as provenance and bib items per release. Care-management families pay for clinical-staff time (99490 = 20 min clinical staff; APCMactor= clinical staff directed by the practitioner), so the wage series for those occupations is the first comparison.Done when the series are queryable by year and occupation, cited in bib, and a notebook overlays 31-9092 wages on the CCM/APCM exposure calendar.
Merged to main as
eb90484(feature b1e06b1; follow-up2d5d12bfor the 2019 file's lower-case headers) and loaded the same day.OEWS (
bls.oews) — the BLS API only serves the latest OEWS year, so history comes from the annualoesm{yy}nat.zipfiles on bls.gov (2013–2024). Those refuse plain scripted downloads (403) but serve a request carrying a full browser header set, whichbls.oews.downloadsends; the zips are cached atdata/bls/oews/. Eachnational_M{year}_dlsheet (xls in 2013, xlsx after;OCC_GROUPthrough 2018 under the 2010 SOC,O_GROUP+ area/industry columns from 2019 under the 2018 SOC, lower-case headers in 2019 only) is normalised to one row per SOC occupation: employment, mean/median hourly and annual wage, 10/25/75/90th percentiles, with*/#/**suppression as NULL and the BLS series-id prefix (OEUN000000000000+ occupation digits) on every row. Loaded: 15,277 + 1,329 = 16,606 rows, 12 releases; one bib Source per release (PUNS6S4N … XPDSWMK8;module:bls,table:bls.oews,source:bls-website,year:N) and acms.ingest_logrow per release with the zip's sha256.CES (
bls.ces) — a closed registry of employment (…01, thousands, SA) and average hourly earnings (…03) series for health care, ambulatory care, offices of physicians, home health, hospitals and nursing/residential care (CES65<industry><type>), pulled through the public API in 10-year × 25-series chunks (BLS_API_KEYwidens to 20 × 50; none is set). Loaded: 2,868 monthly observations, 12 series, 2006–2025; one bib Source per series (urldata.bls.gov/timeseries/<id>), series id on every row.CLI:
stack bls oews [--year]... [--write [--offline]] [--occ 31-9092]...andstack bls ces [--write] [--series ID]... [--annual]. Notebookcode_families.py§7f overlays clinical-staff wages (31-9092 medical assistants, 29-2061 LPN/LVN, 29-1141 RN, 29-1171 NP) and physician-office / ambulatory employment on the family'sbecomes-payable/endsdates from §7c; provenance counts include both tables.First comparison (31-9092, the CCM "clinical staff" occupation): mean annual wage $30,780 (2013) → $34,540 (2018) → $36,930 (2020) → $40,700 (2022) → $44,720 (2024), employment 572k → 793k; offices-of-physicians employment (CES6562110001, SA annual mean) 2,732k (2021) → 3,008k (2025).
Tests: 28 unit (
tests/bls/), 7 CLI (tests/cli/test_bls_cli.py), notebook structure + live run green; pre-commit suites (bls, cli, notebooks) passed.