The emission_factor_value table

One published value of a factor: the headline number, its gas splits, the vintage it was characterised under, and everything needed to judge whether it fits.

Fields#

field type required example meaning
id uuid yes The row's own identifier. Consumers address a factor by its slug, not by this.
source_key text yes 'efv1-'+H(publisher, release, factor source parts + value discriminators); recipe version lives in the prefix. UNIQUE is a collision-detection net: never silently deduped.
content_hash text 'ch1-'+H(raw fields); source-edit detector
emission_factor_id uuid yes re-linkable: corrections move membership, not identity
publisher_id uuid yes identity self-contained even if re-linked
release_id uuid yes release fixes the system_model (dim 3)
source_row_id uuid The raw line this value came from (E: traceability).
data_type text How specific the number is to the thing you bought, and nothing else (dim 9). CHECK-closed at three words: specific is the ILCD "specific dataset" - ONE product from one named plant, which a supplier link alone never implies; generic is a default standing in for a measurement, with no producer attached; average is a mean over several producers, which is where a market, national, sector or operator-wide figure lands. The publisher's own word survives verbatim in source_row.raw.
reference_year integer yes The year the value DESCRIBES: the publisher's data or activity year: Ember 2019 is electricity generated in 2019. Where the publisher states no data year, the edition year stands in; each library's basis is recorded in its own file under docs/ef-libraries/. Use it to judge how old a number is, and to pick a vintage out of a multi-year series. It is not when we ingested the row (updated_at) and not when the publisher shipped it (release.released_on).
publisher_valid_from date Start of a validity window the PUBLISHER states. Populated only where the publisher prints one: today essentially the CBAM regulatory schedule. NULL is the normal case and does not mean 'not valid'. Never derived from reference_year. Use it only to honour a publisher's forward schedule: to choose a value use is_latest, to date the data use reference_year. It is not on factors_flat: read it through the view's value_id. It is not the view's applies_from_year, which we derive from reference_year and never cap with this date.
publisher_valid_to date The date the PUBLISHER withdraws the value: ÖKOBAUDAT's dataSetValidUntil, co2emissiefactoren.be's 'Geldig tot'. Use it to detect a retirement: a factor the publisher did not republish in its newest edition. NULL means the publisher stated no end, not 'current forever'. A value past its publisher_valid_to still serves, by design; the audit flags it advisory rather than dropping it. It is not on factors_flat: read it through the view's value_id. It does not cap the view's applies_to_year.
is_latest boolean yes Marks the value currently served for its lineage. Exactly one per lineage.
is_default_indicator boolean yes Marks the one value served when the caller does not pick a characterization. Exactly one per factor per release, which is what makes the served view a single row per factor.
is_latest_reference_year boolean yes The mechanical year-vintage pick: true on the row(s) at MAX(reference_year) within (factor, release, approach, radiative_forcing): maintained by the loader (_refresh_is_latest_reference_year), never adapter-supplied. Orthogonal to is_default_indicator (methodology) and to is_latest (release/lineage currency): a consumer that does not name a year reads is_latest AND is_default_indicator AND is_latest_reference_year. Not enforced by a unique index: parallel co-current siblings tied at the same top year (EXIOBASE's 7 GHG characterizations) all carry it true, same as is_latest.
value_co2e_native double precision yes The headline number, per one canonical unit, under the publisher's own global-warming-potential vintage. On all but a labelled few it is exactly as published: the publisher's own total, never a sum of the components below. co2e_origin says which shape it came from. source is the publisher's printed total and computed_from_gases is its printed per-gas vector summed under the stated GWP set; both are transcriptions, and both leave emission_factor.is_derived false. summed_from_children is the exception and the only shape no publisher printed: open_ef summed an exact cover of that factor's own slices because the publisher prints the parts and not the whole, and such a row sets is_derived as well. Filter on is_derived to choose a reporting convention: under the GHG Protocol combustion and upstream fuel are reported apart, under ISO 14083 they are added.
co2e_origin text yes Which shape the headline came from, closed by CHECK: source = the publisher printed the total; computed_from_gases = it printed a per-gas vector and we summed that vector under the stated GWP set; summed_from_children = nobody printed a total and open_ef summed an exact cover of this factor's own slices (emission_factor.is_derived).
co2e_basis text Which CO2e the headline counts: whether biogenic carbon and land use are inside. Two factors on different bases are not comparable however close the numbers look.
value_co2_native double precision CO2 component, native vintage.
value_co2_fossil_native double precision Fossil CO2 component, native vintage.
value_ch4_native double precision Methane component, native vintage.
value_ch4_biogenic_native double precision Biogenic methane component, native vintage.
value_n2o_native double precision Nitrous oxide component, native vintage.
value_hfcs_native double precision HFC basket component, native vintage.
value_pfcs_native double precision PFC basket component, native vintage.
value_sf6_native double precision Sulphur hexafluoride component, native vintage.
value_nf3_native double precision Nitrogen trifluoride component, native vintage.
value_other_native double precision Remaining greenhouse gases the publisher groups together, native vintage.
value_co2_biogenic_native double precision Biogenic CO2 component, native vintage.
value_co2_luluc_native double precision Land-use and land-use-change CO2 component, native vintage.
value_removals_native double precision Removals the publisher accounts for, native vintage. Negative by convention.
value_co2_normalized double precision The _normalized twin of each gas leg (rev 13), on exactly the rule the headline follows: re-characterized where gwp_normalization_basis says 'recharacterized', and otherwise a verbatim copy of the native leg. NULL only where the publisher ships no such leg at all, so a consumer reading the _normalized set alone never has to fall back to the native one.
value_co2_fossil_normalized double precision Fossil CO2 component, moved to the target vintage.
value_ch4_normalized double precision Methane component, moved to the target vintage.
value_ch4_biogenic_normalized double precision Biogenic methane component, moved to the target vintage.
value_n2o_normalized double precision Nitrous oxide component, moved to the target vintage.
value_hfcs_normalized double precision HFC basket component, moved to the target vintage.
value_pfcs_normalized double precision PFC basket component, moved to the target vintage.
value_sf6_normalized double precision Sulphur hexafluoride component, moved to the target vintage.
value_nf3_normalized double precision Nitrogen trifluoride component, moved to the target vintage.
value_other_normalized double precision Remaining greenhouse gases the publisher groups together, moved to the target vintage.
value_co2_biogenic_normalized double precision Biogenic CO2 component, moved to the target vintage.
value_co2_luluc_normalized double precision Land-use and land-use-change CO2 component, moved to the target vintage.
value_removals_normalized double precision Removals the publisher accounts for, moved to the target vintage. Negative by convention.
gwp_method_native text yes ar4 / ar5 / ar6 / mixed / unknown / none (none = pure-CO2, no GWP)
gwp_horizon_years integer yes 20/100/500
characterization_model text named LCIA method, snake_case; else NULL
gwp_origin text yes source / assigned / inferred
value_co2e_normalized double precision yes The same headline, moved to the one target vintage so it can be added to another library's. Always populated: where the move is not exactly derivable the native number is copied through and labelled unconverted, so this is the only headline column a consumer needs to read. Sum it only across rows where gwp_normalization_basis is not unconverted.
gwp_method_normalized text yes The vintage these numbers are ACTUALLY on: 'ar6' for every converted basis, and the row's own gwp_method_native for 'unconverted'.
gwp_normalization_basis text yes HOW the measure was obtained, and the ONE column that says whether it may be summed across libraries: native (already the target vintage: a verbatim copy) / invariant (pure-CO2 value, GWP=1 in every vintage) / recharacterized (per-gas legs divided by the native GWP, re-multiplied by the target) / unconverted (not derivable: the native number, native vintage). The cross-library-comparable set is WHERE gwp_normalization_basis <> 'unconverted': not gwp_method_normalized = 'ar6', which an AR6 row on a GWP20/GWP500 horizon also satisfies while answering a different question.
calculation_approach text location_based / market_based / NULL
radiative_forcing text with / without / NULL (n/a)
grid_mix text Grid or network accounting mix (refines calculation_approach): production / consumption (location); residual / supplier_specific / green (market). NULL where the carrier publishes no location/market duality of its own, which is most non-electricity - but NOT all of it: japan_moe's statutory basic (kiso) / adjusted (chouseigo) pair is published for city gas and district heat as well as electricity, and this axis is what separates a menu's two legs. Pair-enforced with calculation_approach, so a supplier-specific gas coefficient cannot be typed market_based without it. In value_discriminators; is_default marks the sensible default per method (consumption for location, residual for market).
grid_mix_origin text Who put the grid_mix there (MOD-0042, D5): 'source' when the publisher printed a value for that mix, 'assigned' when open-climate.ai added the value under rule G (the Protocol's green zero on a residual's factor: AIB's 31 greens, then green_e, nve, nga_australia). NULL exactly when grid_mix is NULL, so a filter on the axis never has to special-case a value the axis does not apply to. A green zero keeps co2e_origin = 'source': it is the Protocol's value, not an estimate.
currency_year integer For a monetary factor, the price level the value is expressed in, bounded [1990, 2100]. A monetary factor is only meaningful with it: use it to deflate or inflate spend before applying the factor. It is a price year, not a publisher date, and it is independent of reference_year.
price_basis text producer / purchaser / basic
value_qualifiers jsonb Library-family-specific value discriminators that are NOT a cross-library typed axis: a single jsonb bag, keys validated by the loader against the declared VALUE_QUALIFIER_KEYS registry (no dumping ground). First occupant: EN 15804 EPD scenarios, {"scenario": "S2"}. Any value_discriminators input to the source_key hash MUST be readable from a typed column or here: never only from inside the hash or source_record (queryability contract).
uncertainty_pct double precision The publisher's stated uncertainty, as a percentage of the value.
data_quality_rating_native double precision The publisher's OWN rating, on the publisher's OWN scale. Meaningless without data_quality_scheme_native: 'lower is better' on one scheme and the number of axes both vary, so two ratings from different publishers must NOT be compared. Cross-library comparison is what data_quality_normalized below is for.
data_quality_scheme_native text Which scheme the rating on this row is expressed in. A rating never travels without it.
data_quality_detail_native jsonb scores on registered axes only, e.g. {TeR,GR,TiR,P}; NULL if none
data_quality_normalized text yes The one quality ordinal that is comparable across publishers. Values at the problematic floor are excluded from the serving view.
data_quality_reason_normalized text Why the tier is what it is, or why a 0 is real: 'structural_zero', 'green_electricity_zero', 'rounded_to_zero', 'context_dependent_basis', 'tiny_denominator_extreme'; the loader stamps 'library_prior' / 'no_native_signal' when nothing else explains the tier. Every 0 on a servable factor carries one, so the read path can exclude it by reason. A reason never forces a tier: only an adapter override floors, and a correct zero keeps its derived tier (MOD-0015). NULL when a native quality signal set the tier. See ingest.loader.
unit_conversion_factor double precision yes What the source's number was multiplied by to reach the canonical unit.
activity_raw text The activity string exactly as the source wrote it.
region_raw text NULL when the source ships no region
unit_raw text The unit label exactly as the source wrote it, before canonicalisation.
source_native_id text publisher's own id when present
source_native_id_kind text e.g. 'ademe_identifiant'
source_status text e.g. ademe 'valide_generique' / 'archive'
source_link text The publisher's own link for this record.
source_record jsonb yes Adapter-authored per-value provenance: a selected + renamed + lightly cleaned subset of source fields (+ derived fields, e.g. the resolved system_boundary); feeds content_hash for edit detection. The full, untouched line lives in source_row.raw (one per artifact line, shared by sibling values): that is the ALL-fields-verbatim archive, not this.
ingested_at timestamp yes When we loaded the row.
updated_at timestamp yes OUR pipeline bookkeeping, not a publisher date: when we last wrote this row. Use it for cache invalidation (WHERE updated_at > :last_sync) and for nothing else. When the number was dated is reference_year; when the publisher shipped it is release.released_on.

Referenced by#

value_unit_bridge.value_id.

Notes#

Every stored measure is native: as the publisher published it, under the publisher's own global-warming-potential vintage. Beside it sits a _normalized twin of the headline and of all thirteen gas legs, moved to a single target vintage. The twin is populated on every row: where the move is not exactly derivable the native numbers are copied through and the row is labelled unconverted, so a consumer reads one set of columns and never falls back to the native set by hand. gwp_normalization_basis is what to filter on: an unconverted row is one you cannot honestly add to another library's.

The serving view answers now: exactly one current value per factor. Superseded vintages are not lost: they stay in this table, off the served surface, keyed by reference_year, and that is how a consumer answers which value applies to my 2019 inventory. Query this table directly for that and order by reference_year yourself: is_default_indicator is elected once per factor per release, so it only ever marks the newest year.