USGS - Mineral Resources Data System (MRDS)
global mining deposits + producing facilities - 2016 freeze (~237K facilities)
Source
Feed (what to expect)
Free bulk CSV + RDBMS ZIP, frozen 2016-03-15; live-fetched but content never changes.
Quirks
Reconciliation
Schema
Feeds (axes)
Record kinds
Identifier schemes
Phase 1 desk landscape, written 2026-05-05. Reference document for the MRDS fetcher rebuild against the v1 multi-dimensional Classification schema landed in commit
ebb0962. Cross-references:docs/adr/007-multi-dimensional-classification.md,docs/DATASOURCES.md,src/strata/models/, strata's production fetcher atstrata/src/strata/fetchers/usgs_mrds/, rendered Cu deposit-atlas atstrata/results/deposit_atlas/copper.md.
Live-data corrections (verified 2026-05-05 against the actual
mrds-csv.zip):
- Bulk URL is
https://mrdata.usgs.gov/mrds/mrds-csv.zip(with the/mrds/segment), NOThttps://mrdata.usgs.gov/mrds-csv.zipas the original §1 wrote. The bare URL returns 404. All sibling artefacts also live under/mrds/.- The bulk denormalised CSV exposes 46 columns -
plant_type,plant_id, andoperatorare NOT among them. Those columns live in the normalisedrdbms-tab.zipdump only. Initially (commit5768124) the v1 fetcher dropped those paths and emitted no OperatorReference rows + no Plant-specific role fan-out; subsequently (commit9e523b5, see RDBMS-upgrade callout below) the fetcher gained those paths back by consuming the RDBMS dump alongside the bulk CSV.scoreis a single-letter grade A-E (D=70 % / C=14 % / E=8 % / B=8 % / A=0.3 %), NOT the integer 0-100 the §3.1 row claims. The implementation maps A/B → HIGH, C → MEDIUM, D → LOW, E → PLACEHOLDER.Other landscape claims hold up: 304,632 rows, ~80 % US, the dev_stat
- commodity vocabularies, the model-code brace-delimited shape, approximate-year qualifier semantics. Live first-fetch admitted 237,087 facilities (78 %) - Occurrence rows + missing-coordinate rows account for the 67 K dropped.
This is the reference for porting the v0 (strata-shaped)
MRDS fetcher onto the v1 schema spine: slim Facility + multi-row
Classification + FacilityIdentifier + OperatorReference +
LifecycleEvent + FacilityAttribute. The landscape below names every
load-bearing MRDS field, maps it to its v1 destination, and surfaces the
schema gaps that may need an ADR-grade decision before the rebuild lands.
RDBMS-dump upgrade landed (2026-05-05, commit
9e523b5). The v1 fetcher now downloads BOTHmrds-csv.zip(~24 MB) andrdbms-tab-all.zip(~118 MB). The bulk CSV remains the spine (universe of 237 K admitted facilities + identity + coords + commodity
lifecycle); the RDBMS dump layers depth on top via per-dep_id joins:
- Ownership.txt →
OperatorReferencerows (87,032 facilities with operator-chain history; Owner-Operator fans out to OWNER + OPERATOR; deterministicentity_idkeyed on company_id or sha1(owner_name)).- Production_detail.txt + Resources.txt + Resource_detail.txt →
FacilityAttributetime series (annual production + resource estimates + grades).- Materials.txt → tuple-valued
ore_minerals/gangue_mineralsattributes.- Workings.txt →
workings_type/workings_area/workings_depthphysical-site dimensions.- Names.txt + Reference.txt + Holdings.txt →
alternate_names/bibliographic_references/land_holding_typesattributes.- Deposits.txt plant_tp / plant_ident / mill_meth / min_meth →
process_role+process_technologyClassifications (Smelter / Refiner / Mill / Acid Plant disambiguation; Smelter/Refiner fans out to two roles).- Deposits.txt disc_yr / deposit_size →
discovery_year/deposit_size_classattributes.Live ingest count after the upgrade: 2,508,581 records across the resolved store (vs. 1,854,724 pre-upgrade - 35 % growth from per-dep_id depth). Sections §3.7 / §4.4 / §4.9 below describe the currently-implemented behaviour for plant rows + operator emission; earlier text below those headings is preserved as historical design rationale.
Publisher. U.S. Geological Survey, Mineral Resources Program (Reston, VA). Owning division historically the National Minerals Information Center; the dataset itself is a 1996 merger of two predecessors:
The migrated harmonisation produced today's denormalised record set;
both the legacy mrds_id (pre-merger MRDS records) and mas_id
(pre-merger MAS records) are preserved as columns on each row, and a
new system-generated dep_id (12-digit numeric) is the canonical
primary key.
License. US federal-government work. The formal MRDS metadata
record at mrdata.usgs.gov/metadata/mrds.html
declares both Access Constraints: none and Use Constraints: none.
The applicable statutory authority is 17 U.S.C. § 105 ("works of
the United States Government" are not eligible for copyright
protection). The USGS open-data conventions
(usgs.gov/information-policies-and-instructions/copyrights-and-credits)
add the standard agency-attribution courtesy: cite USGS as the source
even though redistribution is unrestricted. License code FF should
register: public_domain (jurisdiction US).
Citation (canonical).
Mason, G.T. and Arndt, R.E., 1996, Mineral Resources Data System
(MRDS): U.S. Geological Survey Data Series 20,
https://doi.org/10.3133/ds20.
Edition: 20160315. Publisher: USGS, Reston, Virginia.
A secondary DOI exists for the record-quality scoring tables
(doi.org/10.5066/P9DYLWMP).
Public landing page. https://mrdata.usgs.gov/mrds/ - file-format options published below.
File formats published (verified 2026-05-05).
| Format | URL | Size | Granularity |
|---|---|---|---|
| Single denormalised CSV (zipped) | https://mrdata.usgs.gov/mrds/mrds-csv.zip | 23 MB | one row per deposit, all attribute columns flattened |
| Shapefile (zipped) | https://mrdata.usgs.gov/mrds/mrds-trim.zip | ~10 MB | per-point geometry plus attribute subset |
| Normalised tab tables (compact) | https://mrdata.usgs.gov/mrds/rdbms-tab.zip | 20 MB | multi-table dump, key fields only |
| Normalised tab tables (full) | https://mrdata.usgs.gov/mrds/rdbms-tab-all.zip | 118 MB | multi-table dump, every domain-table + lookup |
| KML / KMZ | https://mrdata.usgs.gov/services/mrds.kmz | varies | Google Earth viewer |
| GeoJSON | not published as bulk file; available per-record via ?format=geojson query suffix on show-mrds.php | - | per-record |
| WMS / WFS | https://mrdata.usgs.gov/services/wms?layers=mrds, https://mrdata.usgs.gov/services/wfs?layers=mrds | - | live tile/feature service |
| Per-record HTML / XML / JSON | https://mrdata.usgs.gov/mrds/show-mrds.php?dep_id=NNN[&format=xml\|json] | - | record-by-record |
The single denormalised mrds-csv.zip is the canonical bulk-ingest
artefact and what the FF fetcher should target. The
rdbms-tab-all.zip carries richer normalised relations (per-deposit
ore minerals, per-deposit references, etc.) that the denormalised CSV
collapses into pipe-separated cells; FF v1 does not currently need
those, but flag for v1.1 if geochemistry queries become first-class.
Dataset frozen at 2016-03-15. Verified - the MRDS metadata record
publishes Edition: 20160315, and the MRDS landing page
carries an explicit notice: "As of 2011, USGS has ceased systematic
updates to MRDS." The 2016 date is the last file-system mtime push;
no content refresh has occurred since. The bulk URL still resolves
to the 2016 snapshot today (2026-05-05) - verified by HEAD request
and content-length match. The successor dataset USMIN is US-only
and not a replacement; it warrants its own fetcher when needed (out
of scope for the MRDS port).
Global coverage statistics. 304,328 entity points (deposit / occurrence / plant records) worldwide per the formal MRDS metadata. Geographic skew (from strata's loaded copper subset, which is representative): ~80 % of records are US; Chile, Peru, Mexico, Canada round out the top 5 non-US jurisdictions. Older records (pre-2000 MAS imports) typically have spotty operator + grade data; modern entries (post- 2005) are richer but cover only the high-value deposits curated for USGS deposit-model studies. Per-status fan-out for Cu (a useful proxy): 3,931 producer + 18,345 past_producer + 7,564 prospect + 12,161 occurrence + 558 plant + 2,374 unknown (see copper.md).
The bulk ZIP. mrds-csv.zip (23 MB). Contains one CSV file
named mrds.csv (~360 MB uncompressed). UTF-8 encoded with a
BOM (utf-8-sig at decode) - strata's parser uses
encoding="utf-8-sig" to strip it. Comma delimiter, double-quoted
fields, RFC-4180 CSV semantics. Header row carries the column names
shown in §3 below.
The mrds.csv primary file. ~304,328 data rows. Fully
denormalised - many-to-many relationships in the source database
(commodities, ore minerals, references, etc.) are collapsed into
pipe-separated or comma-separated values within single cells. Fields
that USGS publishes as multi-row child tables in the normalised
RDBMS dump (rdbms-tab-all.zip) flatten into delimiter-packed cells
here:
commod1 / commod2 / commod3 columns,
each potentially comma-separated ("Copper, Gold, Silver") and
optionally hyphen-qualified ("Copper-primary, Gold-byproduct").ore cell as comma-separated descriptor.model cell, brace-delimited and numbered
("{53: Porphyry Cu, 17: Skarn Cu}").hrock_unit / hrock_type (single string each).Sibling files. None inside mrds-csv.zip - that archive is
single-CSV-only. The richer rdbms-tab-all.zip archive (118 MB)
expands to 36 tables: deposits, ownership, production
(+ production_detail), resources (+ resource_detail), materials,
workings, names, references, holdings, plus lookup vocabularies. As of
commit 9e523b5 (2026-05-05) FF v1 consumes both archives: the
denormalised bulk CSV remains the spine for facility identity / coords /
lifecycle, and the RDBMS dump feeds eleven domain tables for operator
chains, production / resource time series, mineralogy, workings, and
plant disambiguation (see top-of-doc upgrade callout). Cell-packed
multi-values inside the bulk CSV are still handled via defensive
splitting per §7.
Provenance metadata USGS publishes.
10.3133/ds20 (canonical); 10.5066/P9DYLWMP
(record-quality scoring tables). Both stable.20160315 - exact byte hash
of the bulk CSV is not published, but the edition tag plus the
record count (304,328) is the de-facto integrity claim.score column on every row - USGS-published
estimate of information completeness for that record (varies wildly
across the 304k records; useful for FF confidence-tiering at parse
time).The FF fetcher should record source_url=https://mrdata.usgs.gov/mrds/,
citation per the canonical citation above, license=public_domain,
and stamp source_hash from the sha256 of the on-disk
mrds-csv.zip at fetch time (matches the BaseFetcher pattern from
the v0 MSHA fetcher).
The denormalised CSV publishes the following columns in this order
(verified against mrdata.usgs.gov/mrds/about.php).
The "v1 destination" column points each MRDS field to where it lands
in the FF schema. Drop = not carried (out of scope for v1, or
already covered by another column). JM = stored under
Facility.jurisdictional_metadata as a free-form key (the v1 escape
hatch - promote to a structured field via ADR if it becomes
load-bearing). Sample values are drawn from the verified Bingham
Open Pit (dep_id=10069296), Bingham Canyon Plant (dep_id=10129805),
San Manuel Smelter (dep_id=10234965), and the Cu deposit-atlas tally.
| Column | Type | Description | Sample | v1 destination | Coercion notes |
|---|---|---|---|---|---|
dep_id | str (12-digit numeric) | System-generated unique ID, never reused | "10069296", "10129805", "10234965" | FacilityIdentifier(scheme=usgs_mrds_dep_id, source_value=raw) - also derives the canonical entity_id placeholder for OperatorReference rows | trim; reject empty; preserve as string (leading zeros possible) |
mrds_id | str | Legacy MRDS-database record ID (pre-1996 system) | "W002888", "DC14257" | FacilityIdentifier if non-null (scheme would be usgs_mrds_legacy_id - needs registry insert) | trim; null → omit row |
mas_id | str (10-digit) | Legacy MAS / MILS record ID (pre-1996 BOM system) | "0040210030" | FacilityIdentifier if non-null (scheme usgs_mas_id, registry insert) | trim; null → omit row |
url | str | Per-record show-mrds.php URL | "https://mrdata.usgs.gov/mrds/show-mrds.php?dep_id=10069296" | Drop (derivable from dep_id) | - |
score | int | USGS information-completeness score | 60, 90 | Stored on each emitted Provenance via the confidence parameter - score → ConfidenceTier (>=70 HIGH, 30-69 MEDIUM, <30 LOW) | parse_int; null → MEDIUM default |
| Column | Type | Description | Sample | v1 destination | Coercion notes |
|---|---|---|---|---|---|
site_name | str | Current preferred name | "Bingham Open Pit Mine", "(Facility) San Manuel Copper Smelter" | Facility.canonical_name | strip leading "(Facility) " prefix when dev_stat="Plant"; preserve case as published |
names | str | Pipe-or-semicolon-separated alternate / historical names | "Bingham Canyon Mine; Utah Copper" | JM (mrds_alt_names) | preserve as raw string |
| Column | Type | Description | Sample | v1 destination | Coercion notes |
|---|---|---|---|---|---|
latitude | float (WGS84) | Decimal degrees N | 40.52077, -31.35 | Facility.latitude | range-check [-90, 90]; coerce to None if invalid (legacy sign-flip bugs documented in source) |
longitude | float (WGS84) | Decimal degrees E | -112.1458 | Facility.longitude | range-check [-180, 180]; coerce to None if invalid |
region | str | UN region code or USGS region descriptor | "North America" | JM (mrds_region) | trim |
country | str | Country name (free-form, English) | "United States", "Chile" | Facility.country_iso2 via name → ISO-2 lookup | non-trivial; strata leaves as free-form country_raw. FF v1 must do the ISO-2 lookup at parse time. Add a country_name_to_iso2 helper in _values.py seeded with the ~200 distinct values present in MRDS |
state | str | Sub-national region (state / province) | "Utah", "Antofagasta" | Facility.region | trim |
county | str | County or sub-state district | "Salt Lake" | Facility.locality | trim |
| Column | Type | Description | Sample | v1 destination | Coercion notes |
|---|---|---|---|---|---|
dev_stat | enum-str | Development status (6 values) | "Producer", "Past Producer", "Prospect", "Occurrence", "Plant", "Unknown" | Facility.status + drives Classification process_role mapping (see §4); occurrence drops the row entirely | normalise to lowercase + snake_case; "Past Producer" → past_producer |
oper_type | enum-str | Operation type (11 values) | "Surface", "Underground", "Surface-Underground", "Placer", "Offshore", "Well", "Processing Plant", "Leach", "Brine Operation", "Geothermal", "Unknown" | Classification(dimension=process_technology, taxonomy=ff_process_technology, code derived) - surface/underground informs sub-stage; processing_plant cross-checks dev_stat=Plant | enum-mapping helper; unknown → omit Classification |
dep_type | str (free-form) | General deposit / resource type - narrative descriptor | "Porphyry Cu", "VMS", "Sediment-hosted" | Classification(dimension=process_technology, taxonomy=ff_process_technology) when present + JM (mrds_dep_type_raw) for full string | sparse - 88.6 % of records (~269,516) are blank per USGS metadata. Defer-to-model when both populated (model is more disciplined) |
prod_size | enum-str | Production magnitude (Y/N/S/M/L/U) | "Large", "Medium", "Small" | Classification(dimension=capability_scale, taxonomy=ff_capability_scale) - Small→commercial_small, Medium→commercial_large, Large→mega | rough mapping; sparse field - most rows null |
ore | str | Comma-separated ore mineral names | "Bismuthinite, Chalcopyrite, Galena, Gold, Molybdenite, Pyrite, Bornite, Chalcocite, Covellite" | JM (mrds_ore_minerals) - single string; v1.1 may extract per-mineral rows | preserve raw; high-frequency tokens worth promoting to a future GeochemistryRecord type |
gangue | str | Comma-separated gangue mineral names | "Barite, Garnet, Orthoclase, Quartz, Rhodochrosite" | JM (mrds_gangue_minerals) | preserve raw |
other_matl | str | Comma-separated other materials | "Quartz monzonite, latite" | JM (mrds_other_materials) | preserve raw |
orebody_fm | str | Ore body form / shape descriptor | "Stockwork", "Vein", "Disseminated" | JM (mrds_orebody_form) | preserve raw |
work_type | str | General workings type | "Open Pit", "Adit" | JM (mrds_work_type) | preserve raw - overlaps with oper_type |
model | str (brace-delimited) | Numbered USGS deposit-model codes | "{53: Porphyry Cu, 17: Skarn Cu}", "{208: Sedimentary exhalative Zn-Pb}" | Classification(dimension=process_technology, taxonomy=ff_process_technology) - split-and-emit per code; raw string also preserved in JM (mrds_model_raw) | parse brace-delimited list; emit one Classification per model code; reference USGS deposit-model numbering as a sub-taxonomy under ff_process_technology |
alteration | str | Alteration description | "Potassic, phyllic, propylitic" | JM (mrds_alteration) | preserve raw |
conc_proc | str | Concentrating process | "Flotation", "Cyanidation" | When dev_stat=Plant: Classification(dimension=process_technology, taxonomy=ff_process_technology); else JM | parse one process per token |
ore_ctrl | str | Ore control descriptor | "Stratigraphic", "Structural" | JM (mrds_ore_control) | preserve raw |
reporter | str | Person/organisation that authored the record | "USBM Intermountain Field Operations Center" | Drop (USGS-internal data-entry metadata) | - |
hrock_unit | str | Host rock formation name | "Bingham Stock" | JM (mrds_host_rock_unit) | preserve raw |
hrock_type | str | Host rock lithology | "Quartz monzonite" | JM (mrds_host_rock_type) | preserve raw |
arock_unit | str | Associated rock formation name | "Oquirrh Group" | JM (mrds_assoc_rock_unit) | preserve raw |
arock_type | str | Associated rock lithology | "Quartzite, limestone" | JM (mrds_assoc_rock_type) | preserve raw |
structure | str | Structural description | "Caldera margin" | JM (mrds_structure) | preserve raw |
tectonic | str | Tectonic setting | "Continental arc" | JM (mrds_tectonic) | preserve raw |
ref | str | Bibliographic reference text | varies | Drop (verbose narrative; v1 doesn't carry citation rows on Facility) | - |
| Column | Type | Description | Sample | v1 destination | Coercion notes |
|---|---|---|---|---|---|
yr_fst_prd | int (YYYY) | Year of first production | 1868, 1904 | Facility.commissioning_year + LifecycleEvent(commissioned, event_date=date(YYYY,1,1)) | parse_year with [1700, 2100] guard; sentinel zeros → None |
yfp_ba | str | Before/after qualifier on yr_fst_prd | "<" (=before), ">" (=after), "" | If </> → drop year (treat as approximate; do not emit commissioned event); JM (mrds_yfp_qualifier) preserves the qualifier | - |
yr_lst_prd | int (YYYY) | Year of last production | 2008, 2009 | When dev_stat=past_producer: Facility.decommissioning_year + LifecycleEvent(decommissioned, event_date=date(YYYY,12,31)). When dev_stat=producer: latest production year - JM (mrds_last_production_year); does not trigger decommissioning event | parse_year |
ylp_ba | str | Before/after qualifier on yr_lst_prd | "<", ">" | If </> → drop year; JM (mrds_ylp_qualifier) | - |
disc_yr | int (YYYY) | Discovery year | 1863 | JM (mrds_discovery_year) - FF v1 has no Discovery LifecycleEvent type; flag for ADR if discovery dates become load-bearing | parse_year |
dy_ba | str | Before/after qualifier on disc_yr | "<", ">" | JM (mrds_dy_qualifier) | - |
prod_yrs | str | Free-text production-history descriptor | "1904-2008", "intermittent 1850-1880, 1920-1940" | JM (mrds_prod_yrs_descriptor) | preserve raw |
discr | str | Discoverer name + organisation | "Captain William J. Webb" | JM (mrds_discoverer) | preserve raw |
| Column | Type | Description | Sample | v1 destination | Coercion notes |
|---|---|---|---|---|---|
com_type | enum-char (M / N / B / E) | Commodity type | "M" (metallic), "N" (non-metallic), "B" (both), "E" (energy) | JM (mrds_commodity_type) - informational only | trim |
commod1 | str (comma-separated) | Primary commodity / commodities | "Copper, Molybdenum, Silver, Gold" | Classification(dimension=commodity_or_product, taxonomy=usgs_commodity, version=mrds_2016) - one row per token, is_primary=True | split on comma; strip hyphen-qualifiers ("Copper-primary"→"Copper"); look up in USGS commodity vocabulary (~150 entries - see §3.7 below) |
commod2 | str (comma-separated) | Secondary commodities | "Lead, Bismuth, Platinum, Zinc" | Classification rows as above with is_primary=False, provenance.context="commod2" | same as commod1 |
commod3 | str (comma-separated) | Tertiary commodities | "Palladium, Nickel, Tellurium, Selenium" | Classification rows as above with is_primary=False, provenance.context="commod3" | same as commod1 |
dev_stat=Plant)When dev_stat=Plant, USGS uses two additional fields that are blank
for non-plant rows. They are documented in the WLCI MRDS user manual:
| Column | Type | Description | Sample | v1 destination |
|---|---|---|---|---|
plant_type | enum-str (13 values) | Primary plant type | "Smelter", "Refiner", "Smelter/Refiner", "Beneficiation (Mill)", "Acid Plant", "Agglomeration", "Direct Reduced Iron Plant", "Leach", "Manufacturing Plant", "Metal Plant", "Pellet Plant", "Pigment Plant", "Sinter Plant", "Synthetic Rutile" | drives Classification(dimension=process_role, taxonomy=ff_process_role) mapping - see §4 |
plant_id | enum-str (~50 values) | Detailed processing method | "Flotation", "Smelter-Pyrometallurgy", "Refiner-Pyrometallurgy", "Solvent Extraction-Electrowin", "Heap Leach-Carbon Column-Merrill-Crowe", "Bayer", "Hall-Heroult" (not in vocabulary; just "Pyrometallurgy Unspecified") | Classification(dimension=process_technology, taxonomy=ff_process_technology) - finer-grained than plant_type |
The full plant_id enum (~50 values) is the most disciplined
process-technology vocabulary in MRDS - far cleaner than the
free-form dep_type. The FF ff_process_technology taxonomy can
seed every value as a sub-code under a mrds_plant_id_v1 extension.
Critical for the §4 process-role mapping for Plant rows.
commod* codelist)Verified from the WLCI MRDS user manual
pp. 10-15: MRDS uses a fixed Commodity lookup table with ~150
distinct commodity strings (ranges from "Abrasive" through
"Zirconium"), each tagged with a Commodity_Group (~80 groups -
"Copper", "Aluminum", "PGE", etc.) and Commodity_Type (M/N/E
single character). Notable conventions:
"Copper Oxide", "Copper Sulfide",
"Iron-Pyrite", "Tin, Tailings" are first-class commodity codes."Gold, Refinery",
"Silver, Refinery", "Lead, Refiner", "Lead, Smelter",
"Tungsten, Mill Concentrate", "Zinc, Refiner", "Zinc, Smelter"
are separate commodities from their unrefined counterparts.
Useful at parse time to cross-confirm dev_stat=Plant rows."REE", "Cerium", "Yttrium" all map
to the Commodity_Group="REE"; "PGE", "Palladium", "Platinum"
etc. all map to Commodity_Group="PGE"."Coal" (and its 4 ranks), "Petroleum (Oil)",
"Natural Gas", "Uranium", "Geothermal", "Peat" are all
present (out of FF mining scope but in MRDS).The FF usgs_commodity taxonomy registry should seed all ~150
commodities at version mrds_2016 with their Commodity_Group as
the parent code. This is distinct from the USGS Mineral
Commodity Summaries vocabulary (~88 commodities, current annual
version mcs2026) - they overlap but differ. The MRDS-vocabulary
seed is for parsing MRDS rows; the MCS-vocabulary seed is for
joining against USGS MYB and USGS MCS data products.
Each MRDS row becomes one Facility (when admissible) plus a fan-out
of multi-record output. The dev_stat value is the master switch.
dev_stat | Becomes a Facility? | Rationale |
|---|---|---|
producer | Yes | Active mine - the canonical Facility case |
past_producer | Yes | Decommissioned mine - historical fact preserved as Facility with status=decommissioned |
plant | Yes | Smelter / refinery / mill - primary FF target for non-mine process_roles |
prospect | Yes | Project-stage facility - status=project; explorers + greenfield projects |
occurrence | No | Geological observation only; no facility was ever built. Drop. |
unknown | Yes, with status=unknown | Default-emit; FF prefers a record-with-unknown-status over silent drop. |
This represents a behaviour change vs strata: strata
emits all 6 statuses as DepositOccurrence (including occurrence)
because its scope is deposit-level mineral inventory, not facilities.
FF should drop occurrence rows since "no facility ever existed at
that point" is a category miss for the canonical-store goal. Per Cu
deposit-atlas counts, this drops ~12,161 of 44,929 Cu rows (27 %) -
a significant filter; document and cite the count in the fetcher's
emit-stats log.
For every admitted Facility:
| Scheme | Source value | Confidence | Notes |
|---|---|---|---|
usgs_mrds_dep_id | row's dep_id | HIGH | The canonical USGS-published primary key; already in SCHEME_USGS_MRDS_DEP_ID |
usgs_mrds_legacy_id | row's mrds_id if non-null | MEDIUM | Pre-1996 legacy ID - needs new IdentifierScheme registry row |
usgs_mas_id | row's mas_id if non-null | MEDIUM | Pre-1996 BoM MAS ID - needs new IdentifierScheme registry row |
The two legacy schemes need IdentifierScheme registry seed rows added alongside the fetcher; flag for the schema-side seeds commit.
industryMRDS doesn't carry NAICS / ISIC codes directly, but commodity + dev_stat permits a high-confidence inference for most rows:
Implementation note (commit 9e523b5, 2026-05-05): the producer /
past-producer commodity → NAICS / ISIC inference still applies. Plant-row
industry inference is now reachable via plant_tp from the RDBMS dump
(Deposits.txt) - see the §4.4 process_role table below for the live
mapping of plant_tp → process_role.
| Pattern | Inferred NAICS 2022 | ISIC Rev 5 | Confidence |
|---|---|---|---|
dev_stat ∈ {producer, past_producer} + commod1 includes Copper | 212230 (Copper, Nickel, Lead, and Zinc Mining) | 0729 (Mining of other non-ferrous metal ores) | MEDIUM |
dev_stat=plant + plant_type=Smelter + commod1=Copper | 331410 (Nonferrous Metal (except Aluminum) Smelting and Refining) | 2420 (Manufacture of basic precious and other non-ferrous metals) | MEDIUM |
dev_stat ∈ {producer, past_producer} + commod1 includes Gold/Silver | 212220 (Gold Ore and Silver Ore Mining) | 0729 | MEDIUM |
dev_stat ∈ {producer, past_producer} + commod1 includes Coal | 212111 (Bituminous Coal and Lignite Surface Mining) - needs oper_type to disambiguate underground | 0510 / 0520 | MEDIUM |
dev_stat ∈ {producer, past_producer} + commod1 includes Iron | 212210 (Iron Ore Mining) | 0710 | MEDIUM |
The mapping table needs ~30 commodity → NAICS pairs to cover the
MRDS commodity vocabulary; seed in _values.py as a
commodity_to_naics_isic dict. Confidence is uniformly MEDIUM
because MRDS data vintage often pre-dates current NAICS revisions
and the inference is by-rule rather than published.
process_roleThe FF-internal 10-stage decomposition (see process_stage.py).
MRDS dev_stat + oper_type + plant_type together drive this:
dev_stat | oper_type | plant_type | process_role Classifications emitted |
|---|---|---|---|
producer | Surface / Underground / Surface-Underground / Placer / Offshore / Well | - | extraction (primary) |
producer | Leach / Brine Operation | - | extraction (primary) + beneficiation (secondary) |
producer | Processing Plant | - | (anomaly; see §6 - should be dev_stat=Plant; emit unknown with WARN log) |
past_producer | (any) | - | same as producer; status differs but role does not |
prospect | (any) | - | none (status=project → no current process_role) |
plant | Processing Plant | Smelter | primary_smelting (primary) |
plant | Processing Plant | Refiner | refining (primary) |
plant | Processing Plant | Smelter/Refiner | primary_smelting (primary) + refining (secondary) - vertically integrated |
plant | Processing Plant | Beneficiation (Mill) | beneficiation (primary) |
plant | Processing Plant | Sinter Plant / Pellet Plant / Agglomeration / Direct Reduced Iron Plant | beneficiation (primary) - DRI may be borderline; BREF-style refinement deferred |
plant | Processing Plant | Acid Plant | chemical_conversion (primary) |
plant | Processing Plant | Pigment Plant / Synthetic Rutile | chemical_conversion (primary) |
plant | Processing Plant | Manufacturing Plant / Metal Plant | fabrication (primary) - coarse; many MRDS plant-type=metal plants are actually rolling mills |
plant | Leach | (n/a) | beneficiation (primary) - heap leach is upstream of refining |
unknown | (any) | (any) | none |
process_technologyThree sources of process-technology evidence in MRDS, in priority order:
plant_id (when dev_stat=Plant) - the cleanest. ~50 values
like "Solvent Extraction-Electrowin", "Smelter-Pyrometallurgy",
"Bayer", "Heap Leach-Carbon Column-Merrill-Crowe". Map to
ff_process_technology codes via a 1:1 enum; some compound values
emit two Classifications (e.g., "Smelter-Pyrometallurgy" →
pyrometallurgy_smelter).
model (any dev_stat) - USGS deposit model codes, brace-
delimited and numbered. Most common values from the Cu deposit-atlas:
| USGS model code | Description | ff_process_technology code |
|---|---|---|
| 17 | Skarn Cu | skarn_cu |
| 18 | Skarn Pb-Zn | skarn_pb_zn |
| 21a | Porphyry Cu | porphyry_cu |
| 23 | Pb-Zn (Mississippi Valley) | mvt_pb_zn |
| 28a | Volcanogenic massive sulfide (VMS) | vms |
| 28b | Kuroko massive sulfide | kuroko_vms |
| 30b | Sediment-hosted Cu | sediment_hosted_cu |
| 53 | Porphyry Cu, skarn-related | porphyry_cu_skarn_related |
| 208 | Sedimentary exhalative Zn-Pb | sedex_zn_pb |
The 30+ most common USGS deposit-model codes seed under
ff_process_technology with parent codes pointing to the
USGS-published deposit-model bulletin (https://pubs.usgs.gov/bul/b1693/)
for traceability. Long tail of model codes: emit raw label,
confidence MEDIUM, mark is_primary=False.
dep_type (free-form, sparse) - fall-back when model is
blank but dep_type is populated. Stored as a Classification
with confidence LOW because the field is not domain-controlled.
commodity_or_productPer §3.6, commod1 / commod2 / commod3 fan out to one
Classification row per (token, role). Taxonomy: usgs_commodity at
version mrds_2016. is_primary is True only for commod1
tokens; commod2 and commod3 rows carry is_primary=False. The
parser must:
"Copper-primary" → "Copper").feedstock_originMRDS doesn't carry feedstock origin directly. Default rules:
dev_stat ∈ {producer, past_producer} (extraction-stage) →
feedstock_origin=primary_ore (HIGH confidence - by definition).dev_stat=plant + plant_type ∈ {Smelter, Refiner, Smelter/Refiner, Beneficiation (Mill), Acid Plant, Sinter Plant, Pellet Plant, Direct Reduced Iron Plant} →
feedstock_origin=unknown (no MRDS column distinguishes primary vs
secondary smelters). Flag: a meaningful fraction of MRDS Plants are
secondary smelters (e.g., the Carrollton Copper Smelter at
dep_id=10288750 is explicitly noted as "secondary smelter" in its
description). Future Phase 1.5 work could enrich this from BREF /
ICSG via cross-reference.dev_stat=plant + plant_type=Manufacturing Plant / Metal Plant →
feedstock_origin=unknown (manufacturing inputs vary).capability_scaleFrom prod_size: "Large" → mega, "Medium" → commercial_large,
"Small" → commercial_small. Sparse field - most rows have it null
and FF emits no Classification. When Y / N flags appear (legacy
encoding), drop with a debug-level log.
MRDS publishes operator and owner narratively rather than as foreign keys. For each admitted Facility:
operator (or owner) field non-null → emit one
OperatorReference with entity_id="usgs_mrds_operator:<dep_id>"
(placeholder reference; the lineage-side resolution against BQ
Legal Entities is Phase 1.5+ work). role=ROLE_OPERATOR,
confidence MEDIUM (operator strings often legacy - Bingham Open
Pit's MRDS row says "Kennecott Copper Corp." which is a legacy
spelling; current operator is "Kennecott Utah Copper LLC").role=ROLE_OWNER, same placeholder ID
scheme, confidence MEDIUM.The placeholder-entity-id approach mirrors the v0 MSHA fetcher's
pattern (entity_id=f"msha_operator:{operator_id}"); the synthesis
layer joins on the placeholder string when reconciling against BQ.
Three event types inferable from MRDS:
| MRDS field | FF event_type | Trigger | Event date | Notes |
|---|---|---|---|---|
yr_fst_prd (when populated and yfp_ba="") | commissioned | All admitted Facilities | date(yr_fst_prd, 1, 1) | confidence MEDIUM (year-precision only) |
yr_lst_prd (when populated, ylp_ba="", and dev_stat=past_producer) | decommissioned | past_producer rows | date(yr_lst_prd, 12, 31) | confidence MEDIUM |
disc_yr (when populated) | (none - no event type for Discovery in v1) | - | - | flagged in §6 as a schema gap - defer; stored in JM for now |
Approximate dates (yfp_ba="<" / ">") drop the year; do not emit a
LifecycleEvent. The full prod_yrs descriptor ("intermittent 1850-1880, 1920-1940")
is NOT parsed into multiple events at v1 - defer to v1.1; preserve
raw in JM.
When MRDS publishes resource estimates (rare - only on well-documented deposits), emit FacilityAttributes:
| MRDS field | FF attribute_name | Unit | Sample |
|---|---|---|---|
Tonnage (from ore_tonn in normalised tables; in denormalised CSV often blank) | resource_tonnage | metric_tons | 1088000000 |
| Cu grade | resource_grade_cu_pct | pct | 0.59 |
| Mo grade | resource_grade_mo_pct | pct | 0.45 |
| Au grade | resource_grade_au_g_per_ton | g_per_ton | 0.39 |
| Length (orebody) | orebody_length_m | m | 3500 |
| Width (orebody) | orebody_width_m | m | 2500 |
| Thickness (orebody) | orebody_thickness_m | m | 800 |
Resource-estimate fields are sparse (<5 % of rows have any tonnage) and the denormalised CSV doesn't expose them as separate columns the same way the RDBMS dump does. Flag as a known v1.1 work item: when the FF schema needs grade-tonnage curves as time series, re-target the RDBMS dump.
The escape hatch for source-native fields without a structured FF
home. Per §3, the following keys are written under
Facility.jurisdictional_metadata (free-form dict[str, str]):
mrds_alt_names, mrds_region, mrds_ore_minerals,
mrds_gangue_minerals, mrds_other_materials,
mrds_orebody_form, mrds_work_type, mrds_model_raw,
mrds_alteration, mrds_ore_control, mrds_host_rock_unit,
mrds_host_rock_type, mrds_assoc_rock_unit, mrds_assoc_rock_type,
mrds_structure, mrds_tectonic, mrds_yfp_qualifier,
mrds_ylp_qualifier, mrds_dy_qualifier,
mrds_discovery_year, mrds_last_production_year,
mrds_prod_yrs_descriptor, mrds_discoverer, mrds_dep_type_raw,
mrds_commodity_type, mrds_oper_type, mrds_plant_id.
Total ~25 keys per Facility maximum; most rows populate <10 of them. Keys are MRDS-prefixed to avoid namespace collision with EPA / MSHA extras when a single Facility has identifiers across sources.
Three real MRDS rows + the v1 records each produces.
Raw MRDS row (dep_id=10069296, fetched via show-mrds.php
2026-05-05):
dep_id=10069296
mrds_id=W002888
mas_id=(blank)
site_name=Bingham Open Pit Mine
names=Bingham Canyon Mine, Utah Copper
country=United States
state=Utah
county=Salt Lake
latitude=40.52077
longitude=-112.1458
dev_stat=Producer
oper_type=Surface
work_type=Open Pit
dep_type=(blank)
prod_size=Large
model={53: Porphyry Cu, 17: Skarn Cu}
commod1=Copper, Molybdenum, Silver, Gold
commod2=Lead, Bismuth, Platinum, Zinc
commod3=Palladium, Nickel, Tellurium, Selenium
ore=Bismuthinite, Chalcopyrite, Galena, Gold, Molybdenite, Pyrite, Bornite, Chalcocite, Covellite
gangue=Barite, Garnet, Orthoclase, Quartz, Rhodochrosite
hrock_unit=Bingham Stock
hrock_type=Quartz monzonite
disc_yr=1863
yr_fst_prd=1868
yr_lst_prd=2008
prod_yrs=1904-2008
operator=Kennecott Copper Corp. (Rio Tinto subsidiary)
owner=Rio Tinto PLC
Emitted v1 records (in stream order):
Facility(
facility_id=fac_<minted_ulid>,
canonical_name="Bingham Open Pit Mine",
latitude=40.52077, longitude=-112.1458,
coordinate_confidence=HIGH, coordinate_source=<prov>,
country_iso2="US", region="Utah", locality="Salt Lake",
status="operating",
commissioning_year=1868, decommissioning_year=None,
jurisdictional_metadata={
"mrds_alt_names": "Bingham Canyon Mine, Utah Copper",
"mrds_ore_minerals": "Bismuthinite, Chalcopyrite, ...",
"mrds_gangue_minerals": "Barite, Garnet, Orthoclase, ...",
"mrds_host_rock_unit": "Bingham Stock",
"mrds_host_rock_type": "Quartz monzonite",
"mrds_discovery_year": "1863",
"mrds_last_production_year": "2008",
"mrds_prod_yrs_descriptor": "1904-2008",
"mrds_oper_type": "Surface",
"mrds_work_type": "Open Pit",
"mrds_model_raw": "{53: Porphyry Cu, 17: Skarn Cu}",
},
canonical_provenance=<prov>, minted_at=<fetch_ts>,
minted_from_source="usgs_mrds_2016",
)
FacilityIdentifier(
facility_id=<above>, scheme="usgs_mrds_dep_id",
source_value="10069296", confidence=HIGH, provenance=<prov>,
)
FacilityIdentifier(
facility_id=<above>, scheme="usgs_mrds_legacy_id",
source_value="W002888", confidence=MEDIUM, provenance=<prov>,
)
# Industry classifications (commodity-inferred)
Classification(dimension=industry, taxonomy=(naics, 2022),
code="212230", is_primary=True, confidence=MEDIUM, ...)
Classification(dimension=industry, taxonomy=(isic, rev_5),
code="0729", is_primary=True, confidence=MEDIUM, ...)
# Process role - extraction (mine)
Classification(dimension=process_role, taxonomy=(ff_process_role, v1),
code="extraction", is_primary=True, confidence=HIGH, ...)
# Process technology - porphyry Cu (skarn-related)
Classification(dimension=process_technology, taxonomy=(ff_process_technology, v1),
code="porphyry_cu_skarn_related", is_primary=True, confidence=HIGH, ...)
Classification(dimension=process_technology, taxonomy=(ff_process_technology, v1),
code="skarn_cu", is_primary=False, confidence=HIGH, ...)
# Commodity - primary (commod1 → 4 rows)
Classification(dimension=commodity_or_product, taxonomy=(usgs_commodity, mrds_2016),
code="copper", is_primary=True, ...)
Classification(dimension=commodity_or_product, taxonomy=(usgs_commodity, mrds_2016),
code="molybdenum", is_primary=True, ...)
Classification(dimension=commodity_or_product, taxonomy=(usgs_commodity, mrds_2016),
code="silver", is_primary=True, ...)
Classification(dimension=commodity_or_product, taxonomy=(usgs_commodity, mrds_2016),
code="gold", is_primary=True, ...)
# (commod2 + commod3: 8 more rows with is_primary=False)
# Feedstock origin
Classification(dimension=feedstock_origin, taxonomy=(ff_feedstock_origin, v1),
code="primary_ore", is_primary=True, confidence=HIGH, ...)
# Capability scale - prod_size=Large
Classification(dimension=capability_scale, taxonomy=(ff_capability_scale, v1),
code="mega", is_primary=True, confidence=MEDIUM, ...)
OperatorReference(
facility_id=<above>,
entity_id="usgs_mrds_operator:10069296",
role=ROLE_OPERATOR, confidence=MEDIUM, ...,
# operator string preserved in provenance.notes:
# "Kennecott Copper Corp. (Rio Tinto subsidiary)"
)
OperatorReference(
facility_id=<above>,
entity_id="usgs_mrds_owner:10069296",
role=ROLE_OWNER, confidence=MEDIUM, ...,
# owner string in provenance.notes: "Rio Tinto PLC"
)
LifecycleEvent(
event_id=evt_<minted_ulid>, facility_id=<above>,
event_date=date(1868, 1, 1),
payload=CommissionedPayload(context="MRDS yr_fst_prd"),
confidence=MEDIUM, provenance=<prov>,
)
# (no decommissioned event - dev_stat=Producer, not Past Producer)
Total: 1 Facility + 2 FacilityIdentifiers + 17 Classifications + 2 OperatorReferences + 1 LifecycleEvent = 23 records for one MRDS row. This is the upper-end fan-out for a fully-curated row; most MRDS rows produce 6-8 records.
dep_id=10045466)A representative past-producer record. Selected because it has operator history without being maximally curated.
Raw MRDS row (selected fields):
dep_id=10045466
site_name=Copper Queen Mine
country=United States, state=Nevada, county=Mineral
latitude=38.3, longitude=-118.6
dev_stat=Past Producer
oper_type=Underground
dep_type=Porphyry Cu-Mo
prod_size=Small
commod1=Copper
commod2=Molybdenum, Silver
yr_fst_prd=1885
yr_lst_prd=1942
prod_yrs=1885-1942 intermittent
operator=(blank)
owner=Anaconda Copper Mining Co. (historical)
Emitted v1 records (compressed):
decommissioned, decommissioning_year=1942.usgs_mrds_dep_id=10045466, HIGH conf.extraction (primary).porphyry_cu_mo (from dep_type; conf MEDIUM -
free-form field, not USGS deposit-model code; model was blank).primary_ore.entity_id="usgs_mrds_owner:10045466",
role=ROLE_OWNER (no operator field; only owner present).Total: ~12 records. Past-producer rows commonly emit fewer records than active producers because operator strings tend to be legacy and ownership-only (not active-operator).
dep_id=10234965)A representative smelter-Plant record from the richer MRDS field surface.
The current bulk-CSV fetcher admits this as a Plant facility but does not
see plant_type, plant_id, or operator.
Raw MRDS row:
dep_id=10234965
mas_id=0040210030
site_name=(Facility) San Manuel Copper Smelter
names=San Manuel Smelter
country=United States, state=Arizona, county=Pinal
latitude=32.61621, longitude=-110.62238
dev_stat=Plant
oper_type=Processing Plant
plant_type=Smelter
plant_id=Smelter-Pyrometallurgy
commod1=Copper
com_type=M
operator=Magma Copper Co.
ownership=Private
note=1973 capacity 200000 TPY
Emitted v1 records:
Facility(
facility_id=fac_<ulid>,
canonical_name="San Manuel Copper Smelter", # "(Facility)" prefix stripped
latitude=32.61621, longitude=-110.62238,
coordinate_confidence=HIGH, ...,
country_iso2="US", region="Arizona", locality="Pinal",
status="unknown", # MRDS Plant rows don't disclose current operating status
jurisdictional_metadata={
"mrds_alt_names": "San Manuel Smelter",
"mrds_oper_type": "Processing Plant",
"mrds_plant_id": "Smelter-Pyrometallurgy",
"mrds_commodity_type": "M",
},
...,
)
FacilityIdentifier(scheme="usgs_mrds_dep_id", source_value="10234965")
FacilityIdentifier(scheme="usgs_mas_id", source_value="0040210030")
# Industry - copper smelting
Classification(industry, naics_2022, "331410", primary=True, MEDIUM)
Classification(industry, isic_rev_5, "2420", primary=True, MEDIUM)
# Process role - primary smelting
Classification(process_role, ff_process_role_v1, "primary_smelting",
primary=True, HIGH)
# Process technology - pyrometallurgy
Classification(process_technology, ff_process_technology_v1,
"pyrometallurgy_smelter", primary=True, HIGH)
# Commodity - copper
Classification(commodity_or_product, usgs_commodity_mrds_2016,
"copper", primary=True, HIGH)
# Feedstock origin - UNKNOWN (MRDS doesn't tell us if primary or secondary)
Classification(feedstock_origin, ff_feedstock_origin_v1, "unknown",
primary=True, HIGH)
OperatorReference(
entity_id="usgs_mrds_operator:10234965",
role=ROLE_OPERATOR, confidence=MEDIUM,
# provenance.notes = "Magma Copper Co. (1991)"
)
# FacilityAttribute - the rare disclosed capacity
FacilityAttribute(
attribute_name="capacity_cu_tpy",
value=200000.0, unit="metric_tons_per_year",
measurement_year=1973, confidence=MEDIUM, ...,
)
# (no LifecycleEvents - yr_fst_prd / yr_lst_prd not populated for plants typically)
Total: ~10 records. Plant rows commonly have richer process-tech
detail (clean plant_id enum) but sparser temporal data.
MRDS data exposes several axes that v1 doesn't have a clean home for. Categorise: defer-to-JM (acceptable v1 compromise) vs schema-extension (ADR-grade work).
disc_yr is widely populated (~30 % of rows) and conceptually a
distinct lifecycle event from commissioned. Per lifecycle.py,
the v1 LifecyclePayload union covers commissioning, expansion,
suspension, resumption, ownership_changed, divestiture, regulatory
action, decommissioning, and correction - but no discovered
event type.
Decision recommendation: defer to JM (mrds_discovery_year)
for v1; flag as candidate for ADR 010 if other sources (Australia
state mining, Brazil ANM) regularly publish discovery dates.
Discovery is mining-specific and may not generalise to chemicals /
semi-conductors / pharma.
Bingham Canyon (dep_id=10129805) carries tonnage=1,088,000,000,
length=3500m, width=2500m, thickness=800m,
Cu_grade=0.59 wt%, Mo_grade=0.45 wt%, etc. The FacilityAttribute
record has measurement_year and unit - the year + unit fields are
sufficient. The schema does not have a structured way to express
"this is a 2010 reserve estimate as opposed to a 2008 production
figure"; both flow through measurement_year with a free-form
attribute_name.
Decision recommendation: emit FacilityAttribute with
discriminating attribute_name (reserve_estimate_tonnage_2010 vs
production_tonnage_2008) and document the convention in the
fetcher's docstring. ADR-grade extension (a new MeasurementType
enum) is over-engineered for v1; revisit when a second source
(Brazil ANM, Australia state mining) starts emitting the same
distinction.
MRDS publishes:
ore - comma-separated ore minerals ("Chalcopyrite, Bornite, Chalcocite, Covellite")gangue - comma-separated gangue mineralshrock_unit / hrock_type - host rock formation + lithologyarock_unit / arock_type - associated rockalteration - alteration assemblage descriptionThese don't fit FacilityAttribute (not quantitative) and don't fit Classification (not taxonomy-bound). For v1 they live in jurisdictional_metadata as raw strings.
Decision recommendation: defer to JM for v1. Future v1.1 may
introduce a GeochemistryRecord type if cross-source analysis
(MRDS + Australia state mining + Brazil ANM, all of which publish
geochemistry) creates a query-time need. Flag for ADR 011.
MRDS publishes per-year tonnage and grade only for the most curated
deposits (~5 % of rows), and the denormalised CSV doesn't expose them
as separate columns. The richer rdbms-tab-all.zip does (multi-row
production-history tables), but FF v1 doesn't ingest that.
Decision recommendation: out of scope for v1. Re-target the RDBMS dump in v1.1 when the canonical store needs grade-tonnage curves. Document the future-work hook in the fetcher's docstring.
The shipped MRDS bulk-CSV path does not carry operator or owner.
Those fields live in the normalised RDBMS dump and, even there, are
single-snapshot legacy strings rather than current legal-entity truth.
The full ownership-transition history that BQ Legal Entities + SEC EDGAR
can expose via LifecycleEvent.ownership_changed events is not in
MRDS.
Decision recommendation: no schema change. The current MRDS fetcher emits no OperatorReference rows. Operator graph fill-in comes from complementary sources (MSHA for US mine operator strings, EPA FRS for non-mine facilities, and BrightQuery Legal Entities for the entity graph) or from a future MRDS RDBMS-dump enrichment fetcher.
plant_idA meaningful fraction (~40 %) of dev_stat=Plant rows have
plant_type populated but plant_id blank. The §4.4 mapping
emits process_role from plant_type (e.g., Smelter →
primary_smelting) but cannot emit a process_technology row when
plant_id is blank.
Decision recommendation: emit no process_technology Classification
when plant_id is blank. Log a counter via the fetcher's
drops_no_process_technology field on the result container.
Acceptable degradation; flag if cross-source enrichment becomes
necessary.
dev_stat=Plant smelter/refinery ambiguityThe MRDS plant_type=Smelter/Refiner value is genuinely ambiguous -
USGS uses it for vertically integrated complexes (smelter +
electrolytic refinery on the same site, like the original El Paso
copper complex). The §4.4 mapping emits two process_role
Classifications (primary_smelting + refining) for this case,
which is the right answer per ADR 007 §6 (one Facility, multiple
process_role rows). But the MRDS row alone doesn't tell us which is
the primary process; both Classifications carry is_primary=True,
which violates the §7 constraint that at most one row per
(facility_id, dimension, taxonomy_id) may be primary.
Decision recommendation: emit both primary_smelting (with
is_primary=True) and refining (with is_primary=False) by
convention; document the convention in the fetcher. Cross-source
data (BREF, ICSG) can flip the primary marker later via correction
events.
import polars as pl
_MRDS_SCHEMA: dict[str, type[pl.DataType]] = {
"dep_id": pl.String,
"mrds_id": pl.String,
"mas_id": pl.String,
"site_name": pl.String,
"names": pl.String,
"country": pl.String,
"state": pl.String,
"county": pl.String,
"region": pl.String,
"latitude": pl.Float64,
"longitude": pl.Float64,
"dev_stat": pl.String,
"oper_type": pl.String,
"dep_type": pl.String,
"prod_size": pl.String,
"model": pl.String,
"ore": pl.String,
"gangue": pl.String,
"other_matl": pl.String,
"orebody_fm": pl.String,
"work_type": pl.String,
"alteration": pl.String,
"conc_proc": pl.String,
"ore_ctrl": pl.String,
"hrock_unit": pl.String,
"hrock_type": pl.String,
"arock_unit": pl.String,
"arock_type": pl.String,
"structure": pl.String,
"tectonic": pl.String,
"yr_fst_prd": pl.String, # parse_year handles it; defensive against trailing decimals
"yfp_ba": pl.String,
"yr_lst_prd": pl.String,
"ylp_ba": pl.String,
"disc_yr": pl.String,
"dy_ba": pl.String,
"prod_yrs": pl.String,
"discr": pl.String,
"com_type": pl.String,
"commod1": pl.String,
"commod2": pl.String,
"commod3": pl.String,
"plant_type": pl.String,
"plant_id": pl.String,
"score": pl.Int32,
}
_MRDS_NULLS: list[str] = ["", "NULL", "null", "N/A", "n/a"]
_values.pydef clean_text(value: str | None) -> str | None: ...
def parse_year(value: str | None) -> int | None: ... # [1700, 2100], drop ≥0 sentinel
def parse_lat_lon(lat, lon) -> tuple[float | None, float | None]: ...
def normalise_dev_status(value: str | None) -> str: ... # → "operating" / "decommissioned" / "project" / "unknown"
def country_to_iso2(value: str | None) -> str | None: ... # seeded ~200-entry dict
def split_commodity_field(value: str | None) -> list[str]: ...
def strip_commodity_qualifier(token: str) -> str: ... # "Copper-primary" → "Copper"
def parse_model_field(value: str | None) -> list[tuple[int, str]]: ... # "{53: Porphyry Cu, 17: Skarn Cu}" → [(53, "Porphyry Cu"), (17, "Skarn Cu")]
def confidence_from_score(score: int | None) -> ConfidenceTier: ...
def normalise_plant_type(value: str | None) -> str | None: ... # 13-value enum lookup
def normalise_oper_type(value: str | None) -> str | None: ... # 11-value enum lookup
def map_commodity_to_naics(commod1_first: str) -> str | None: ...
def map_commodity_to_isic(commod1_first: str) -> str | None: ...
def strip_plant_name_prefix(value: str | None) -> str | None: ... # "(Facility) X" → "X"
def parse_mrds_csv(
zip_path: Path, *, canonical_provenance: Provenance, minted_at: datetime,
) -> Iterator[BaseModel]:
"""Stream Facility/FacilityIdentifier/Classification/Operator/Lifecycle/Attribute records."""
lazy = pl.scan_csv(
zip_path, schema_overrides=_MRDS_SCHEMA,
null_values=_MRDS_NULLS, encoding="utf8-lossy",
truncate_ragged_lines=True,
).select(_MRDS_SCHEMA.keys())
df = lazy.collect(engine="streaming")
for row in df.iter_rows(named=True):
dev_stat = normalise_dev_status(row["dev_stat"])
if dev_stat == "occurrence": # drop occurrences entirely
continue
lat, lon = parse_lat_lon(row["latitude"], row["longitude"])
if lat is None or lon is None: # geospatial-anchorless rows skip
continue
country_iso2 = country_to_iso2(row["country"])
if country_iso2 is None:
continue
facility_id = mint_facility_id()
yield _make_facility(facility_id, row, dev_stat, lat, lon, country_iso2,
canonical_provenance, minted_at)
yield from _emit_identifiers(facility_id, row, canonical_provenance)
yield from _emit_industry_classifications(facility_id, row, canonical_provenance)
yield from _emit_process_role_classifications(facility_id, row, dev_stat,
canonical_provenance)
yield from _emit_process_technology_classifications(facility_id, row,
canonical_provenance)
yield from _emit_commodity_classifications(facility_id, row, canonical_provenance)
yield from _emit_feedstock_origin_classification(facility_id, row, dev_stat,
canonical_provenance)
yield from _emit_capability_scale_classification(facility_id, row, canonical_provenance)
yield from _emit_operator_references(facility_id, row, canonical_provenance)
yield from _emit_lifecycle_events(facility_id, row, dev_stat, canonical_provenance)
yield from _emit_facility_attributes(facility_id, row, canonical_provenance)
Each _emit_* helper is 10-30 lines, returning 0 - N records depending
on which MRDS columns are populated. Total parser surface ~400-500
lines across parse.py (split from _values.py per the v0 MSHA
package shape).
The MRDS fetcher needs the following Taxonomy registry rows
seeded before records can land in the canonical store. Each row
is a single INSERT against the Taxonomy table with the metadata below.
List the schema-side seeds commit needs to land alongside the
fetcher rebuild.
| taxonomy_id | version | publisher | jurisdiction | license | documentation_url | description |
|---|---|---|---|---|---|---|
usgs_commodity | mrds_2016 | USGS | (global) | public_domain | https://mrdata.usgs.gov/mrds/about.php | MRDS commodity vocabulary, ~150 codes; group/type structure preserved. Seeded for the MRDS fetcher to emit commodity_or_product Classifications. |
usgs_commodity | mcs2026 | USGS | US | public_domain | https://www.usgs.gov/centers/national-minerals-information-center/commodity-statistics-and-information | Mineral Commodity Summaries vocabulary, ~88 codes (current). Distinct from mrds_2016; for cross-walk with USGS MYB. Required even for MRDS-only ingest because the §4 NAICS/ISIC inference table normalises through MCS-vocabulary commodity names. |
ff_process_role | v1 | Facility Foundry | (global) | ff_internal | (internal - process_stage.py) | The 10 canonical stages from ADR 007 §4 (extraction, beneficiation, primary_smelting, refining, chemical_conversion, fabrication, assembly, recycling, distribution_use, end_of_life_collection). |
ff_process_technology | v1 | Facility Foundry | (global) | ff_internal | (internal - registry) | FF-internal process-technology vocabulary; seeded with ~30 USGS deposit-model codes (porphyry_cu, vms, skarn_cu, sediment_hosted_cu, mvt_pb_zn, sedex_zn_pb, etc.) plus the ~50 MRDS plant_id enum values mapped through. |
ff_feedstock_origin | v1 | Facility Foundry | (global) | ff_internal | (internal - classification.py) | The 8 canonical values from ADR 007 §5 (primary_ore, primary_intermediate, secondary_new_scrap, secondary_old_scrap, secondary_blackmass, secondary_tailings, mixed, unknown). |
ff_capability_scale | v1 | Facility Foundry | (global) | ff_internal | (internal - classification.py) | The 5 canonical bands (pilot, demo, commercial_small, commercial_large, mega). |
ff_facility_status | v1 | Facility Foundry | (global) | ff_internal | (internal - _registry_ids.py) | The 6 canonical statuses (operating, commissioning, suspended, decommissioned, project, unknown). Note: not a Classification dimension, but the value-set is registered for queryability. |
naics | 2022 | US Census Bureau | US/CA/MX | public_domain | https://www.census.gov/naics/ | Required for the §4.3 industry-inference rows. (Cross-source - also used by EPA FRS, MSHA fetchers.) |
isic | rev_5 | UNSD | (global) | un_attribution | https://unstats.un.org/unsd/classifications/Econ/isic | Required for the §4.3 ISIC industry inference. |
Total: 9 Taxonomy registry rows. Some may already exist (e.g.
ff_process_role v1 from the canonical-stage definitions) - verify
during the schema-side seeds commit. The two USGS commodity vocabularies
are distinct and both needed.
Identifier-scheme registry rows also required (separate from Taxonomy registry but parallel concept):
usgs_mrds_dep_id - already present at SCHEME_USGS_MRDS_DEP_ID.usgs_mrds_legacy_id - needs new IdentifierScheme registry row +
constant SCHEME_USGS_MRDS_LEGACY_ID.usgs_mas_id - needs new IdentifierScheme registry row + constant
SCHEME_USGS_MAS_ID.Total: 2 new IdentifierScheme registry rows alongside the 9 Taxonomy rows.
usgs_mrds_legacy_id,
usgs_mas_id).ff_process_technology v1 covering the most common USGS
deposit-model codes + the MRDS plant_id enum.usgs_commodity mrds_2016
(the full MRDS Commodity table) plus the ~88 codes under
usgs_commodity mcs2026 (the current MCS vocabulary).Once seeded, the fetcher rebuild lands as a single PR layered on the
existing v1 BaseFetcher ABC + cache-strategy infrastructure (per
the v0 MSHA pattern), with ~400-500 lines of fetcher code spread
across release.py, _values.py, parse.py, fetch.py, and
__init__.py. Estimated record-emit volume: **~280k-310k Facilities