Declare, as data, the shared row shape every admin-shares reader emits
and every admin-shares consumer reads: one subnational administrative
unit's reported value and its share of the FAOSTAT container's total,
for one (item_prod_code, indicator_used, year). Readers emit
source-native identifiers and never resolve names to WHEP codes here;
a later resolution step reconciles those once. Unresolved rows keep
level_polity_code == NA visibly rather than being dropped.
There are two measurement columns, value and share, and a row must
carry at least one of them. value may be missing wherever share is
present, which is a first-class case created by a publication
consent and not a gap to be filled; see the section below before
writing anything that assumes an absolute value is there.
admin_shares_schema() is the check_table_schema() contract itself;
admin_shares_prototype() is the zero-row tibble it implies, and the
two cannot drift apart because the prototype is built from the schema
with empty_table_from_schema().
Value
A schema list, as documented in check_table_schema(): closed
(extra_columns = "forbid"), keyed on (area_code, level_polity_code, level, item_prod_code, species_group, indicator_used, year).
Admin-shares table
One row per (area_code, level_polity_code, level, item_prod_code, species_group, indicator_used, year):
area_code: FAOSTAT-style area code of the container – the polity the subnational units sum into, not the unit itself.level_polity_code: the polity code resolved at the row's granted depth (level);NAwhen that depth is not yet resolved to a polity.level: administrative depth granted for this row, a positive integer (1Lis the container's direct subnational units).item_prod_code: WHEP production-item code (seeadd_item_prod_code()/add_item_prod_name()) on a crop row;NAon a livestock row.species_group: the livestock group a livestock row counts, in the vocabularybuild_gridded_livestock()allocates in ("cattle_dairy","pigs","sheep_goats", ...);NAon a crop row. A row names exactly one ofitem_prod_codeandspecies_group.indicator_used: which indicator this row'svalueanchors to, one of"area_harvested","area_planted_or_sown","area_main","area_cultivated","production","yield"for a crop row, or"head_count"(live animals, head) for a livestock row.year: calendar year of the observation.value: the unit's own reported value forindicator_used, in the source's native unit.NAon a row whose source is consented to ship shares only – see Shares-only rows below. Never invented.share: the unit's own value divided by the admin sum across sibling units for the same(area_code, level, item_prod_code, indicator_used, year), taken by the row's own producer over its own units.NAwhere the producer ships values and that sum has not been taken. This package does not fill it in at load: a share derived here from the values in the same table would make the seam gate's value-versus-share identity (R/admin_shares_gate.R, tier A) true by construction, and an identity that cannot fail detects nothing.source: dataset label of the row's producer, e.g."USDA_NASS","Eurostat_apro_cpshr","Eurostat_apro_cpnhr_h","Eurostat_apro_mt_ls_r","Eurostat_ef_lsk_poultry","IBGE_PAM","IBGE_PPM","JRC_subnational_crops", or a tier-2/3 admin-statistics family label. Documented here, not enforced as a closed vocabulary: later tiers add sources this list cannot enumerate in advance, unlikeindicator_used,grainandtreatment_year, which the contract does close. A caller may therefore put any label here, andresolve_admin_shares()will rank it. Where the vocabulary is closed is at the pin boundary: every source in the assembledadmin-sharespin must be declared beforeread_admin_shares()will hand it over, because that artifact carries sources whose values are withheld by a publication consent and an undeclared label is indistinguishable from a new one.tier: data tier of the source,1L-3L.grain: the reporting geography's fineness, one of"admin1","admin2","admin3", in that ascending order. Stored ascharacterrather than an Rorderedfactor:check_table_schema()'s type vocabulary (R/table_schema.R) has no factor type, so the ordering is carried by the vocabulary's declared order rather than by the column's R class. A caller needing genuine ordered comparisons can dofactor(grain, levels = c("admin1", "admin2", "admin3"), ordered = TRUE).concept_break: whether the item concept changed where this row's source or grain took over from another.nuts_version: the NUTS nomenclature version the row's geography was coded under,NAoutside NUTS geographies.source_native_id: the row's identifier exactly as the reader found it in the source;NAfor a row with no native identifier, e.g. one derived rather than read (such as a residual).source_native_name: the row's name exactly as the reader found it, diagnostic only – never joined or matched on.source_id: the producer's immutable identifier, inrow_evidence()'s vocabulary (R/row_evidence.R) – the same value space assource, so an admin-shares table can be handed to the row-evidence family without renaming.source_version: version or vintage of that source,NAwhen the producer has none, exactly asrow_evidence()documents it.recorded_at: when the row was recorded, as an ISO 8601 UTC string ("2026-01-01T00:00:00Z"), the same stamp shaperow_evidence()writes.treatment_year: how this row's year was obtained, one of"observed","interpolated","carried". Reserved for the gap rule; this contract only names the vocabulary.treatment_value: how the row's value was obtained,"observed"(reported by the unit) or"reconstructed"(derived by the source, e.g. from a national total).NAwhen the source does not say, which is every source today; it is never defaulted to"observed".value_flag: a free-text data-quality flag,NAwhen the row is clean.
Shares-only rows
A row may carry share and no value. That is not a defect, not a
missing observation and not a gap for a later step to fill: it is what
a publication consent produces, and the contract admits it on purpose.
The Latin American subnational panel of Infante-Amate, Urrego-Mesa,
Badia-Miro and Aguilera ships to WHEP as derived shares only –
875,514 rows over 142 first-level units of Argentina, Bolivia, Brazil,
Chile, Colombia and Mexico – under the co-author agreement of
2026-09-02 recorded in inst/extdata/admin_stats_pins_manifest.csv.
Its source values are withheld until that panel's own publication, so
WHEP may carry each unit's share of its container's total and nothing
else. Five of those six countries have no other subnational evidence in
this package. Demanding a value would therefore not have improved the
data: it would have dropped five countries out of the subnational
constraint while every balance and conservation check still passed.
A synthetic value is forbidden, in both the forms that tempt:
value = 0satisfies the contract and then enters the allocation as a reported area of zero – a claim the source never made, and one that a downstream reader cannot tell from a real zero.a value back-computed as
share * national totalsatisfies it too, and additionally reconstructs the quantity the consent withheld.
Neither is acceptable, and finding either in code is a defect to report
rather than a shortcut to reuse. A shares-only row travels as a
shares-only row: resolve_admin_shares() ranks candidates on
indicator, grain, tier and run length, none of which reads value, and
allocate_level_crops() (R/spatialize_levels.R) carries a
"share_normalised" denominator for exactly this case.
What the contract does still refuse is a row carrying neither
measurement: ensure_admin_shares() and resolve_admin_shares() abort
on one with class whep_error_admin_no_measure, because such a row
constrains nothing and would enter an allocation as an invisible
abstention.
It equally refuses a non-finite value or share, with class
whep_error_admin_nonfinite. NaN is not a missing measurement: it is
what a 0/0 leaves behind, and since is.na(NaN) is TRUE every
is.na(value) branch downstream would read it as the consented
shares-only case above. Inf is refused with it, which no schema bound
catches either – check_table_schema() guards min and max with
!is.na(values), and value has no maximum.
Examples
admin_shares_schema()
#> $columns
#> $columns[[1]]
#> $columns[[1]]$name
#> [1] "area_code"
#>
#> $columns[[1]]$type
#> [1] "integer"
#>
#> $columns[[1]]$allow_missing
#> [1] FALSE
#>
#>
#> $columns[[2]]
#> $columns[[2]]$name
#> [1] "level_polity_code"
#>
#> $columns[[2]]$type
#> [1] "character"
#>
#>
#> $columns[[3]]
#> $columns[[3]]$name
#> [1] "level"
#>
#> $columns[[3]]$type
#> [1] "integer"
#>
#> $columns[[3]]$allow_missing
#> [1] FALSE
#>
#> $columns[[3]]$min
#> [1] 1
#>
#>
#> $columns[[4]]
#> $columns[[4]]$name
#> [1] "item_prod_code"
#>
#> $columns[[4]]$type
#> [1] "integer"
#>
#>
#> $columns[[5]]
#> $columns[[5]]$name
#> [1] "species_group"
#>
#> $columns[[5]]$type
#> [1] "character"
#>
#> $columns[[5]]$allowed
#> [1] "buffalo" "camels" "cattle_dairy"
#> [4] "cattle_non_dairy" "chickens_broilers" "chickens_layers"
#> [7] "equines" "other" "pigs"
#> [10] "poultry" "sheep_goats"
#>
#>
#> $columns[[6]]
#> $columns[[6]]$name
#> [1] "indicator_used"
#>
#> $columns[[6]]$type
#> [1] "character"
#>
#> $columns[[6]]$allow_missing
#> [1] FALSE
#>
#> $columns[[6]]$allowed
#> [1] "area_harvested" "area_planted_or_sown" "area_main"
#> [4] "area_cultivated" "production" "yield"
#> [7] "head_count"
#>
#>
#> $columns[[7]]
#> $columns[[7]]$name
#> [1] "year"
#>
#> $columns[[7]]$type
#> [1] "integer"
#>
#> $columns[[7]]$allow_missing
#> [1] FALSE
#>
#>
#> $columns[[8]]
#> $columns[[8]]$name
#> [1] "value"
#>
#> $columns[[8]]$type
#> [1] "double"
#>
#> $columns[[8]]$min
#> [1] 0
#>
#>
#> $columns[[9]]
#> $columns[[9]]$name
#> [1] "share"
#>
#> $columns[[9]]$type
#> [1] "double"
#>
#> $columns[[9]]$min
#> [1] 0
#>
#> $columns[[9]]$max
#> [1] 1
#>
#>
#> $columns[[10]]
#> $columns[[10]]$name
#> [1] "source"
#>
#> $columns[[10]]$type
#> [1] "character"
#>
#> $columns[[10]]$allow_missing
#> [1] FALSE
#>
#>
#> $columns[[11]]
#> $columns[[11]]$name
#> [1] "tier"
#>
#> $columns[[11]]$type
#> [1] "integer"
#>
#> $columns[[11]]$allow_missing
#> [1] FALSE
#>
#> $columns[[11]]$min
#> [1] 1
#>
#> $columns[[11]]$max
#> [1] 3
#>
#>
#> $columns[[12]]
#> $columns[[12]]$name
#> [1] "grain"
#>
#> $columns[[12]]$type
#> [1] "character"
#>
#> $columns[[12]]$allow_missing
#> [1] FALSE
#>
#> $columns[[12]]$allowed
#> [1] "admin1" "admin2" "admin3"
#>
#>
#> $columns[[13]]
#> $columns[[13]]$name
#> [1] "concept_break"
#>
#> $columns[[13]]$type
#> [1] "logical"
#>
#> $columns[[13]]$allow_missing
#> [1] FALSE
#>
#>
#> $columns[[14]]
#> $columns[[14]]$name
#> [1] "nuts_version"
#>
#> $columns[[14]]$type
#> [1] "character"
#>
#>
#> $columns[[15]]
#> $columns[[15]]$name
#> [1] "source_native_id"
#>
#> $columns[[15]]$type
#> [1] "character"
#>
#>
#> $columns[[16]]
#> $columns[[16]]$name
#> [1] "source_native_name"
#>
#> $columns[[16]]$type
#> [1] "character"
#>
#>
#> $columns[[17]]
#> $columns[[17]]$name
#> [1] "source_id"
#>
#> $columns[[17]]$type
#> [1] "character"
#>
#> $columns[[17]]$allow_missing
#> [1] FALSE
#>
#>
#> $columns[[18]]
#> $columns[[18]]$name
#> [1] "source_version"
#>
#> $columns[[18]]$type
#> [1] "character"
#>
#>
#> $columns[[19]]
#> $columns[[19]]$name
#> [1] "recorded_at"
#>
#> $columns[[19]]$type
#> [1] "character"
#>
#> $columns[[19]]$allow_missing
#> [1] FALSE
#>
#>
#> $columns[[20]]
#> $columns[[20]]$name
#> [1] "treatment_year"
#>
#> $columns[[20]]$type
#> [1] "character"
#>
#> $columns[[20]]$allow_missing
#> [1] FALSE
#>
#> $columns[[20]]$allowed
#> [1] "observed" "interpolated" "carried"
#>
#>
#> $columns[[21]]
#> $columns[[21]]$name
#> [1] "treatment_value"
#>
#> $columns[[21]]$type
#> [1] "character"
#>
#> $columns[[21]]$allowed
#> [1] "observed" "reconstructed"
#>
#>
#> $columns[[22]]
#> $columns[[22]]$name
#> [1] "value_flag"
#>
#> $columns[[22]]$type
#> [1] "character"
#>
#>
#>
#> $key
#> [1] "area_code" "level_polity_code" "level"
#> [4] "item_prod_code" "species_group" "indicator_used"
#> [7] "year"
#>
#> $extra_columns
#> [1] "forbid"
#>
# A schema-conformant table: two sibling units of one container.
rows <- tibble::tibble(
area_code = c(840L, 840L),
level_polity_code = c("USA-IOWA", "USA-ILLINOIS"),
level = c(1L, 1L),
item_prod_code = c(44L, 44L),
indicator_used = c("area_harvested", "area_harvested"),
year = c(2020L, 2020L),
value = c(1000000, 800000),
share = c(0.42, 0.34),
source = c("USDA_NASS", "USDA_NASS"),
tier = c(1L, 1L),
grain = c("admin1", "admin1"),
concept_break = c(FALSE, FALSE),
nuts_version = NA_character_,
source_native_id = c("19", "17"),
source_native_name = c("Iowa", "Illinois"),
source_id = c("USDA_NASS", "USDA_NASS"),
source_version = c("2021-05", "2021-05"),
recorded_at = "2026-01-01T00:00:00Z",
treatment_year = c("observed", "observed"),
value_flag = NA_character_
)
nrow(check_table_schema(rows, admin_shares_schema()))
#> [1] 2
# A shares-only pair, as a consented source ships it: `share` present,
# `value` absent, and the contract satisfied.
consented <- rows |>
dplyr::mutate(
value = NA_real_,
share = c(0.79, 0.21),
source = "admin-stats-latam",
source_id = "admin-stats-latam",
tier = 3L
)
nrow(check_table_schema(consented, admin_shares_schema()))
#> [1] 2
