Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/gunnar

crates/gunnar-recipe/Cargo.toml

# gunnar's **build thing** — the recipe, as a crate.
#
# ## What this is
#
# The 2026-08-06 design (`workspace_nordisk/PLAN.md`, "BUILD THING — MERGAD
# DESIGN") makes a build thing a **published crate: code, not data**. Not a wasm
# module shipped inside the artifacts it builds, and not a register somebody has
# to search. dwarves depends on this crate — or names it by coordinate
# (`gunnar-build-thing:<version>`) before any artifact exists — and asks it what
# gunnar can be built into.
#
# ## It is a normal workspace member again, as of 2026-08-06
#
# It used to carry its own `[workspace]` table and sit in the parent's
# `exclude`, for ONE reason with an exact end: it needs
# `nornir_build_thing::contract` (`Coordinate`, `PaneKind`, `Receipt`), which was
# not in the published 0.1.4, so the dependency reached the sibling `../edda`
# checkout — and a member would have dragged that requirement onto every
# `cargo build` of gunnar, breaking the reuse rule's "builds
# standalone from a fresh clone".
#
# `nornir-build-thing 0.1.5` went to crates.io on 2026-08-06 (verified against
# the sparse index), which is the end that was written down. The `path` is gone,
# the dependency resolves from the registry like any other, and that rule holds without
# a sibling checkout.
#
# ## It is publishable, and that is load-bearing
#
# `gunnar-cli` BUILD-depends on this crate — its `build.rs` writes the receipt
# into every gunnar binary — and `xtask/tests/publish_order.rs` forbids a
# publishable crate from naming an unpublishable one, in any spelling. That
# guard is right: `cargo publish -p gunnar-cli` could not resolve a
# `publish = false` sibling from the registry, and dropping the `version` to
# leave only the `path` is refused too. So the recipe crate publishes, which is
# also what the design says it does — wave 0, before the things it builds.
[package]
name = "gunnar-recipe"
# 0.1.1 (2026-10-26, lane GUN-INSTALL / G-BOTH, the R5C publish): master differs from crates.io, so
# it gets its own version; additive against crates.io 0.1.0, built against nornir-build-thing 0.2.6.
version = "0.2.0"
edition = "2021"
rust-version = "1.85"
license.workspace = true
# On the `cargo install gunnar` chain (owner order 2026-10-22).
publish = true
authors.workspace = true
repository.workspace = true
description = "gunnar's build thing: which atoms (gunnar-server, gunnar, gunnar-cli, gunnar-ui, gunnar-solo) can be assembled into which delivery columns (exe, container, iso-installer, iso-live, rpm), as typed Rust rather than a build-time-checked TOML."
readme = "README.md"
# Not published by hand from here. The suite releases through
# `dwarves workspace-release`, and this crate is wave 0 of it: it publishes
# before the things it builds, because their receipts name it by coordinate.

[lib]
# **A PLAIN RLIB, and that is the whole point of this crate existing.**
#
# It used to be `crate-type = ["cdylib", "rlib"]` here, because the same source
# had to be both the native library gunnar's build scripts link and the wasm32
# module the forge loads. That is still true of the RECIPE — it is just not true
# of one crate any more, and the reason is measured:
#
# For a target whose `crate-type` includes `cdylib`, cargo emits **no
# `--extra-filename`**, so every unit of it writes the same
# `target/debug/deps/libgunnar_build_thing.rlib`. This crate is reached BOTH as
# a `[build-dependencies]` (gunnar-cli's and gunnar-server's `build.rs` write
# the receipt through `emit::write_receipt`) and as a normal workspace member,
# and resolver 2 keeps those two feature-resolutions apart — so there were two
# units, two `-C metadata` hashes, and one filename. Whichever finished last
# won, and the build script linked the loser:
#
#   mold: error: undefined symbol: gunnar_recipe::emit::write_receipt
#
# for a function that is in the source AND in the rlib on disk. MEASURED
# 2026-09-03: `cargo build --workspace` from cold went **red 6 times out
# of 8**, and a warm re-run was always green, which is exactly why it survived
# for so long — see cargo#6313.
#
# A plain rlib gets an `--extra-filename`, so the two units coexist. The cdylib
# obligation moved to `crates/gunnar-build-thing`, a shim that nothing
# build-depends on and which therefore has exactly one unit.


[dependencies]
# The contract (`Coordinate`, `PaneKind`, `Receipt`), the receipt WRITER
# (`receipt::ReceiptBuilder` / `receipt::emit`, used by `emit::write_receipt`),
# the declaration types (`BuildVariant`, `BuildVariantSet`, `ContainerBuild`,
# `IsoBuild`) and the `plugin::BuildThing` trait this crate implements.
#
# From the REGISTRY, not a path: see the header. `0.1.9` (2026-08-26): the
# `laws` module (`tests/bijection_laws.rs`) and `InstallerBuild.kernel_donor`
# (the mirror in `recipe.rs`) exist from 0.1.9; before that `0.1.7`, because
# `ArtifactKind::Installer` and the installer-variant reversal (kind =
# "installer" as a legal variant kind, resolved by NAME to the
# `[[build.installer]]` payload) do not exist in 0.1.5 — whose loader parses an
# unknown kind string to `Exe` SILENTLY, so under the old pin the
# `gunnar-installer` pointer variant would load as an executable and the parity
# mirror would agree with the lie. (0.1.5 was itself pinned over 0.1.4 for
# `contract` and `receipt`, for the same reason.)
#
# `default-features = false`: this crate is a declaration and computes nothing,
# so it wants none of the heavy build machinery (bollard, the plugin host).
#
# ## 0.1.10 (2026-08-27) — the settings tree, the iso's kernel edge, and the end
# ## of the `tree-laws` feature
#
# The pin was 0.1.9 for one day and for one reason, written down here at the
# time: the settings tree (`tree`, `flags`, the tree laws B/C/D, ops 11–13 over
# the wasm ABI) and `IsoBuild.kernel_donor` lived on edda main and NOT on
# crates.io. A `[patch.crates-io]` onto `../edda` was considered and REFUSED —
# a patch table is a structural publishing blocker in this constellation, and
# `cargo publish` verifies against the registry, which would not compile a
# field only the sibling has.
#
# `nornir-build-thing 0.1.10` reached crates.io on 2026-08-27 (wave-3
# decision R1). So the pin is a plain version bump, no patch, and the
# consequences the note promised are taken in the same breath:
#
# * `IsoBuild` carries `kernel_donor`, so the loader gunnar's own binaries LINK
#   sees the live medium's kernel edge. `tests/iso_edge_linked.rs` was RED on
#   purpose against 0.1.9 and is green on the bump — by the pin advancing, not
#   by the test being weakened.
# * `InstallerBuild`, `ContainerBuild` and `IsoBuild` grew `edges` (the general
#   consumption edge beside `kernel_donor`), which `recipe.rs`'s
#   every-field-named mirrors now name — that naming is exactly why the addition
#   got a decision instead of defaulting in silently.
# * the `tree-laws` feature is GONE: the gates it held are in the default set.
# Through the WORKSPACE entry (root `Cargo.toml`), which is a path dep on the
# sibling edda checkout since 2026-08-30. The refusal of a
# `[patch.crates-io]` recorded above still stands and is not what changed: a
# path dependency with the version kept is the road the reuse rule sanctions, the one
# `nornir-git` already walks, and the `path =` is deleted the day 0.1.11 is on
# crates.io. What it BUYS is the paragraph above's promise: `kernel_requires`
# inside an option row is spellable here now, so the closure gunnar declares is
# visible to gunnar's own reader instead of only to the composing forge.
nornir-build-thing = { workspace = true }

# The error type `nornir-build-thing`'s own writer returns. Named rather than
# wrapped: `emit::write_receipt` is called from a `build.rs`, where the useful
# thing is the whole `{:#}` chain saying which flaw refused the receipt.
anyhow = "1"

# No `toml` dev-dependency. The parity guard (`tests/toml_parity.rs`) reads the
# file this crate migrated from with `BuildVariantSet::load_file` — the SAME
# loader dwarves uses. A second parser here would be a second opinion about what
# the file says, which is the one thing that guard must not have.

[dev-dependencies]
# The plugin HOST — wasmtime — for `tests/wasm_plugin.rs` only: it loads this
# crate's own wasm32 build through the generic `PluginHandle` (no gunnar
# dependency on the host side, which is the forge's situation) and holds its
# answers equal to the native ones. Same registry version as the normal
# dependency above, so the two features unify onto one crate; nothing here
# reaches the shipped rlib or the wasm module.
# `cargo-container`: `tests/cli_matrix.rs` builds the sibling dwarves' declared row in its
# declared toolchain container when none is built (the same feature gunnar's xtask turns on).
nornir-build-thing = { workspace = true, features = ["plugin-host", "cargo-container", "provenance"] }
# **The CLI-door matrix** (`tests/cli_matrix.rs`) emits ONE nornir-testmatrix row
# per variant, on the same channel `gunnar-server/tests/appliance_matrix_rows.rs`
# uses (`functional_status` → `NORNIR_TESTMATRIX_OUT` JSONL). From the REGISTRY
# with the emit MODE on: a dev-dependency reaches no shipped artifact.
nornir-testmatrix = { version = "0.2", features = ["testmatrix"] }
# The artifact digest the matrix row carries beside the receipt (`tests/cli_matrix.rs`).
sha2 = "0.11"
# `tests/rows_equal_cargo_install.rs` reads each row's package manifest (its bins and
# feature table) to tell which binary its `cargo install` line leaves (G-BOTH-2).
toml = "1"

[build-dependencies]
# The recipe's own content hash, computed over its own sources at compile time.
# See `build.rs`: a receipt names the recipe by `krate:version:hash`, and the
# hash is the only field that can tell two builds of the same version apart.
sha2 = "0.11"

# No `[features]`. The `tree-laws` gate that lived here is GONE: it existed only
# while the settings tree was on edda main and not on crates.io, and
# `nornir-build-thing 0.1.10` published on 2026-08-27. `tests/tree_laws.rs` and
# the tree halves of `wasm_plugin.rs` / `toml_parity.rs` / `cli_matrix.rs` are in
# the DEFAULT set. Its coda says why it was gated for a day.