Code Lists
The vocabulary for code lists — governed, externally maintained sets of coded entries (language tags, licence identifiers, currency codes, media types, time zones) that are projected into Kanonak packages from their source of truth by a producer, never hand-typed. One CodeList record per generated package states where its entries came from and which revision of the source they reflect; every entry carries the same few facts, so one renderer, one deprecation rule and one lookup serve the whole family.
A code list is reference data that someone else governs: the IANA language subtag registry, the SPDX licence list, ISO 4217 currencies, the IANA media-type and time-zone registries. Each is an authoritative, slowly changing list of coded entries with labels and a lifecycle (entries get added, deprecated, and replaced). Kanonak packages need to reference those entries as resources, not carry them as strings, so each list becomes a package under codes.kanonak.org — and because the list is governed elsewhere, the package is generated, never authored.
One way in. Every code list is produced by a producer: a small plugin, implementing the SDK's package-producer contract, that reads the source in the format the source is expressed in (record-jar, CSV, JSON, XML) and projects it into a package through the SDK's PackageBuilder. Format readers are shared; the mapping from one source's records to one list's entries is the plugin. The producers and the generated packages live in the kanonak-protocol/code-lists repository, published as their own publisher at codes.kanonak.org — kanonak.org keeps the protocol and its vocabularies, including this one; a projection of someone else's data lives with its own publisher. The producers run on demand — never on a schedule, so a source that revises often does not become a stream of package versions nobody asked for. A run fetches the source, compares its digest with the last projection, projects on change, validates, and opens a pull request adding the new version. A person decides when to run it and merges; the site deploy publishes. Nothing is ever overwritten or deleted.
The version is the source's own. A generated package's version is derived from the source's version marker — the registry's file date (2026-09-17 becomes 2026.9.17), a list version (3.27 becomes 3.27.0) — never from when the producer ran. The same source bytes always produce byte-identical output, and the pipeline proves it by projecting twice.
Provenance is in-band. Each generated package holds one Code List resource naming each
Source it was read from (a
prov.Standard with its URL, the Source Version the source declared, and the
Source Digest of the exact bytes read), the
Producer that projected it, and the
Entry Class and
Entry Count. A list may have several sources (a current and a historic list); the first is the one the package version derives from. A reader can verify the package against its sources without trusting the pipeline.
Every entry looks the same. An Entry carries its
Code (the string the source uses — the BCP 47 tag, the SPDX identifier, the currency code), an
rdfs.label, optional Alternative Label alternatives, and when it is retired,
Deprecated plus
Superseded By pointing at its replacement. Domain-specific facts are layered on by each list's own vocabulary (for language tags, the
language-tag package). The uniform floor is what lets one renderer, one deprecation warning and one lookup work across the whole family.