# 0055: Native redistributable packages carry corresponding-source artifacts - Status: Accepted - Date: 2026-10-09 - Extends: [0049](0049-module-package-v1.md). ADR 0049 withholds distributable-release status from a package until its licence handling is proven. This ADR adds what proving it means for a native package that redistributes copyleft code: a sibling corresponding-source artifact, and a fail-closed gate for public distribution. Module Package v1 is unchanged, and `packageFormat` stays **1**. - Decides: the item [ADR 0052](0052-reviewed-license-supplements.md) deferred, "the legal and compliance determination of source obligations for each redistributed binary, and how a determination is recorded", as a project policy. Reviewed supplements are unchanged in purpose and format. - Related: [ADR 0051](0051-module-package-license-material.md), whose rules for a module's own licence are unchanged. ## Context A native Module Package (ADR 0049) copies native dependencies into its `node_modules` exactly as built. The first one, the packager's native proof with sharp, redistributes `@img/sharp-libvips-linux-x64`. That is one shared object with about 29 libraries built into it. Several are under the GNU LGPL, and cairo and some Rust crates are under the MPL. ADR 0052 made the licence and notice side work. A reviewed supplement adds the licence, copyright, and notice files the package omits, with the exact upstream source each came from. But ADR 0052 was explicit that carrying material is not meeting obligations. The LGPL and the MPL also oblige whoever distributes the binary to make the corresponding source available. For a library linked into a larger work, that includes what a recipient needs to rebuild the library and use a modified version. Recording upstream URLs does not do that: URLs move, tags are rewritten, and a mirror is somebody else's promise. Until this was decided, every native package containing such components was blocked from public distribution, and the blocker had no defined way to be lifted. ## Decision ### Native packages may contain copyleft native dependencies A native Module Package may redistribute native dependencies under the LGPL, the MPL, or a similar licence with source obligations. It may be **distributed publicly** only when it is released together with a **corresponding-source artifact** that meets this ADR. A package whose artifact cannot be produced and verified is not approved for public distribution. This is Ekklesia's **project compliance policy**: a conservative rule the project holds itself to. It is not legal advice, and it is not legal certification. Repository review of the artifact, its inputs, and its instructions is project and code review. It does not replace professional legal review, and nothing built from this ADR may claim that it does. ### Supplements and source artifacts do different jobs - **A reviewed supplement (ADR 0052)** identifies and verifies the licence and notice material for a redistributed binary. It travels inside the package, in `THIRD_PARTY_NOTICES`. - **A corresponding-source artifact** carries the source, patches, build definitions, and rebuild and relink instructions for the covered native components. It travels beside the package, as a separate release artifact. A supplement alone never satisfies the source-availability policy. A source artifact never replaces the supplement or `THIRD_PARTY_NOTICES`. ### What the artifact contains For each covered native dependency the package redistributes, the artifact contains: - the exact source the binary was built from, as bytes, not as references: - its build definitions; - the source archive of every library compiled into it; - every patch the build applied; - every source package a language package manager resolved for the build; - the source of any runtime library the toolchain linked into it; - the licence and copyright material: the reviewed supplement, and the files inside the sources; - **instructions** that are technically actionable. They name what the artifact corresponds to and its target, and say how to apply the patches and rebuild the covered library. They also say how a rebuilt or modified library replaces the redistributed one in the installed module, and which toolchain and configuration to use, or point to the included build definitions; - a deterministic, machine-readable manifest of every component and file, each with its digest, plus the human-readable provenance. Components that are not part of the binary are left out, each with its reason recorded: build-only, test-only, or another platform's. The exception is a build-time input needed to rebuild the covered library, such as a source package a build script requires. That is included and marked as build-only. Host system libraries and general-purpose build tools are not redistributed, and the instructions name the versions they need. ### It is tied to exact inputs, and verified before it is written - **Bound to the binary.** An artifact names each covered dependency by package name, version, and the content digest a supplement is matched by (ADR 0052). It names the module identity and target of the package it accompanies. An artifact for one version of a binary never satisfies another. - **From reviewed inputs only.** The inputs come from a checked-in, reviewed **source recipe** per covered dependency version. The recipe records each component's name, version, origin, relationship to the binary, and licence material, and each source file's and patch's size and SHA-256. - **Acquisition is separate from construction.** Obtaining the recorded bytes may use the network, in an explicit preparation step that stores them in a local cache keyed by content digest. Constructing the artifact is offline. It reads only the cache and checked-in files, verifies every byte against the recipe before writing anything, and never fetches or trusts a current upstream response. - **Deterministic.** The same inputs produce the same artifact, byte for byte, in any working directory: normalized relative paths, fixed ownership, modes, and timestamps, sorted entries, and no machine-specific path. ### Binary and source are linked by recorded digests A public release of a native package with covered components consists of sibling artifacts: - the Module Package archive and its SHA-256 (ADR 0049); - the corresponding-source archive and its SHA-256; - machine-readable **redistribution metadata** recording: - the package archive's name and SHA-256; - the module identity and target; - each covered dependency's name, version, licence, and content digest; - the supplement and recipe it was assembled from; - the source archive's name and SHA-256, and the SHA-256 of its manifest; - a **release notice**, displayed alongside the binary wherever it is offered. It says, in substance, that the release includes third-party software under licences including the GNU LGPL or the MPL, and that corresponding source and build and relink materials for the covered native dependencies are in the accompanying artifact, named by its exact file name and SHA-256. A reviewer can therefore tell exactly which source artifact corresponds to which redistributed binary, from digests, without guessing from file names. The source archive is never placed inside the Module Package. `THIRD_PARTY_NOTICES` stays as it is, and never duplicates the source. ### Public distribution fails closed Building and testing packages stays unrestricted: the packager produces native packages exactly as before, for development, CI, and private use. **Public redistribution approval** is a separate gate. For a package intended for public distribution, the gate requires that: - the package's native dependency inventory is known; - every covered dependency has its reviewed supplement and source recipe; - the corresponding-source artifact is present; - every digest matches; - the artifact's manifest validates against the recipe and the archive's own contents; - the release notice names the exact artifact. If any requirement fails, approval fails. Bundled (not copied) code under such a licence is not handled by this mechanism, so the gate refuses it rather than approving it. ### Retention, and no rewriting history - Ekklesia keeps a release's corresponding-source artifact for as long as it distributes, or supports access to, the matching binary release. Nothing deletes one automatically while that binary remains available. - The bytes of a source artifact for an existing binary release are never replaced under the same identity. - A correction is a new release, or an explicitly versioned compliance artifact that the redistribution metadata names. History is never silently replaced. ### What this ADR does not do - It does not change any module's own licence, or ADR 0051's rules for it. The module's own source obligations are met by the module's own repository, as before. - It does not make **runtime downloading** an acceptable workaround. Fetching a copyleft library at run time instead of redistributing it moves the obligation rather than meeting it, makes installations depend on a third party, and breaks ADR 0048's self-contained installed modules. It is not the preferred path. - It does not change Module Package v1, the verifier's acceptance of a package, or the content of existing supplements. ## Consequences - Native modules that need copyleft native libraries, starting with sharp's libvips, can be distributed publicly under a defined, checkable policy, instead of being blocked indefinitely. - Each covered dependency version needs a reviewed source recipe, as it needs a reviewed supplement. A dependency bump needs both before public distribution works again. - Releases carry an artifact many times larger than the package itself (about 200 MB for libvips 1.3.4, against a 9 MB package), and Ekklesia commits to retaining it. - Constructing the artifact needs the verified source cache. Acquisition happens once per recipe, not on every build. ## Alternatives - **Treat supplements, source URLs, or a written offer as sufficient.** Rejected: URLs and offers depend on third parties and on time. This policy requires the source itself, retained with the release. - **Put the source inside the Module Package.** Rejected: installations would store hundreds of megabytes they never need, and the package format would change for a distribution concern. - **Download sources while constructing the artifact.** Rejected: a release would depend on mutable remote responses. Acquisition is explicit and verified, and construction is offline. - **Download native libraries at run time.** Rejected, as above. - **Per-dependency special cases in code.** Rejected for the same reason as in ADR 0052: recipes are reviewed data, and the mechanism knows no particular library. ## Deferred - Hosting and serving source artifacts for published module releases, and the release CI that runs the gate and keeps the verified source cache. - Corresponding source for bundled copyleft code, if a module ever needs it. - Recipes provided by module repositories, alongside the question ADR 0052 deferred for supplements.