The emission_factor table

The factor itself: one lineage per publisher, spanning releases and years, with the values attached separately.

Fields#

field type required example meaning
id uuid yes The row's own identifier. Consumers address a factor by its slug, not by this.
publisher_id uuid yes The publisher this belongs to.
factor_source_id text yes The source-anchored identity: 'ademe//36284//Combustion//Combustion', 'exiobase//p06.5//WE'. Frozen per-source recipe (keys.py RECIPE SPEC).
slug text yes ef-ademe-electricite-reseau-france-a1b2c3d4 The published, permanent identifier. Frozen when the factor is first minted and never re-derived; a superseded slug keeps resolving through the alias table.
activity_src_id text yes Groups the region / unit / boundary variants that are the same activity. Stable across releases.
activity_main text yes ONE language per factor, and which one is a retrieval decision rather than a display preference: open_ef.activity_search embeds this column verbatim, while what a reader is shown is resolved per field from emission_factor_text. The rule is the publisher's own language wherever the source shipped a name. Where the adapter GENERATES the name instead, it stores English (the catalogue's default read language) and dates that choice in the library's docs/ef-libraries/.md, unless the generated English would collapse distinctions the native name keeps, which is a declared exemption dated in the same file. That is the ispra-versus-japan_moe case: ispra stores its generated English, japan_moe stayed Japanese while its English named 1,475 of 1,663 factors 'Electricity'. Audited advisory by name_column_language.
activity_detail text The qualifier the publisher adds to the activity name, where there is one.
activity_full text yes Electricite - reseau France continentale The full activity name: the main activity, plus the detail when there is one. This is the search keyword.
description text The publisher's own prose about the factor (preferred-language copy of the description text term). Never a restatement of a typed column: a boundary name or a category path belongs in system_boundary / activity_classification, where a consumer can query it.
usage_definition text A written what-this-covers / when-to-use / caveats paragraph. Ours, not the publisher's, and labelled as generated.
publisher_sector text Flat convenience: top + leaf LABELS of the PUBLISHER'S OWN tree, which is why they carry the prefix: the same string means different things in two libraries and no two libraries share a value. The cross-library axis is open_ef_category, which lives in activity_classification (scheme = 'open_ef_category') and is served as factors_flat.category / .sub_category; it deliberately has no column here, because a factor carries N classification rows across schemes and levels. The typed hierarchy with native codes is open_ef.activity_classification.
publisher_sub_sector text
boundary_profile jsonb This factor's own answers to the boundary questions, overriding the boundary defaults. Sparse: an absent term is not established, never excluded.
region_code text yes Where the factor applies, at whatever grain the publisher modelled: a country, a subdivision, a modelled aggregate.
region_origin text yes source / assigned / inferred
region_raw text Denormalized latest-value raw region, for quick retrieval without a join.
unit_code text yes The canonical unit the value is expressed per.
unit_family text yes mass/energy/volume/monetary/...
basis_kind text yes Tier-3 basis annotation: 'canonical' (unit basis self-describing) or 'context_dependent' (the printed unit does not say what "1 unit" is, so a value is producible only through a validated per-line query-time bridge, never a blind conversion). A context-dependent factor carries a basis-qualified unit_code (kg_n, m2_nfa) so a plain-kg/m2 query cannot blind-match it. reference_basis is the structured descriptor (the generalized reference product), required when context_dependent; its kind is a closed vocabulary validated at ingest (ingest.vocabulary). A canonical factor carries none, except a gas volume on l, whose gas_volume descriptor names the publisher's metering conditions (MOD-0010).
reference_basis jsonb For a unit that is not self-describing (a mass of nutrient, a qualified area), what the basis actually is and what a conversion would need.
system_boundary text yes What this factor counts: see the system boundary vocabulary. The single most important field for deciding whether two numbers may be compared.
system_boundary_origin text yes Whether the boundary was stated by the publisher, assigned by us, inferred, or is genuinely unknown.
system_boundary_raw text The literal source boundary token when system_boundary is a semantic aggregate (EN 15804 'A1-A3' -> cradle_to_gate keeps 'A1-A3' here); NULL when the code already is the raw token. A pure annotation.
parent_id uuid Set on a decomposition child (a stage or contribution of another factor), always together with parent_relation: both or neither. Aggregate only over rows where this is null, or you will double-count. Null is not evidence that a factor has no parts: it means either that the publisher printed no separable envelope, or that its parts were published in a shape we do not link.
parent_relation text How the child sits under its parent, and it follows the arithmetic rather than the publisher's wording. sums_to_parent means the siblings of that split exhaust the parent, so they may be summed within one split: and never added to the parent itself. contained_by_parent means the child is one itemised slice of a larger envelope whose remainder was not published, so it may never be summed with anything.
root_id uuid yes The top of this factor's parent chain, stored: its own id when parent_id is NULL, else its parent's root_id. Lets a served list group every part under its top-level factor without walking parent_id per row (plan FRN-0013). Kept by the two writers of parent_id -- the loader re-roots a publisher after linking, a mint cascades the demoted members' subtrees to the new parent (db_open_ef.roots); mint-* --refresh never rewrites it. Not a CHECK: the loader links, then re-roots, in two statements.
is_derived boolean yes TRUE when open_ef COMPUTED this headline by summing a whole-group exact cover of reconciling children, rather than transcribing a number the publisher printed. It exists because one total cannot serve both reporting conventions: under the GHG Protocol combustion is Scope 1 and well-to-tank is Scope 3.3, reported apart and never added on one line, while ISO 14083 / GLEC require exactly that sum. So is_top_parent AND NOT is_derived is the Scope-1/3.3 view and is_top_parent AND system_boundary = 'well_to_use' the ISO 14083 one (factors_flat names the parent-less flag that way). The value row says the same thing again on co2e_origin ('summed_from_children'), deliberately: two independent columns, so a consumer reading either half cannot mistake a derived row for a published one. See plan MOD-0006.
is_estimated boolean yes TRUE when open-climate.ai computed this factor's values by a RULE from a published base value and reference statistics (MOD-0042: the transmission-and-distribution and fuel-chain legs of an electricity factor whose publisher prints generation only). Narrower than is_derived, which it implies (CHECK below): a derived total sums the publisher's own printed slices, an estimated leg is a number no publisher printed. The value row says it again on co2e_origin ('estimated_from_reference'). A parent with an estimated child is estimated too.
is_epd boolean yes TRUE when this factor is (a module of) an Environmental Product Declaration: a third-party-verified declaration a named declarant publishes for one product or product group (EN 15804 / ISO 14025). Set by the ADAPTER at ingest, refreshed on re-ingest like any annotation. ÖKOBAUDAT: every ILCD subType except generic dataset, whose rows are the database's own modelled background data (Sphera / GaBi), which no manufacturer declared. A supplier link is NOT the same thing: a supplier-specific grid tariff (miterd, japan_moe) names a company and is no EPD, and an industry EPD's declarant is a trade association. Served as factors_flat.is_epd, an explorer facet.
supplier_id uuid The named counterparty, where the factor describes one.
labels jsonb {lang: text}: denormalized passport
last_ingest_version bigint yes Change tracking: the ingest_run.ingest_version that last mutated this factor's annotation layer. Lets a consumer sync "what changed since" with no diffing (WHERE last_ingest_version > :last_seen). Re-stamped with updated_at on every annotation refresh (loader; one rule, both fields).
created_at timestamp yes When the row was first written.
updated_at timestamp When the row was last rewritten.

Referenced by#

activity_classification.factor_id, emission_factor.parent_id, emission_factor.root_id, emission_factor_alias.emission_factor_id, emission_factor_text.factor_id, emission_factor_value.emission_factor_id, external_factor_map.emission_factor_id, route_default.factor_id.

Notes#

Identity is source-anchored: (publisher, factor_source_id) and nothing else. Everything readable here beyond that pair (the activity prose, region, unit, boundary, classifications) is a harmonisation annotation: improving one never re-keys the factor, and never changes a published slug.