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

nordisk/dwarves

.nornir/holger-build-thing-design.md

holger build target — design

Class: design · Function axis: f0 the holger build target (the whole) · f1 the pipeline-as-data · f2 the plan/wiring resolve · f3 the run-time build seam · f4 the local CLI verb · f5 the server RPC (remote-driven) · f6 the thin-client verb (--server, a real gRPC round-trip) Strict: this file states only what the holger build target IS — its parts and why. Sibling how-to: holger-build-thing-guide.md; zero-knowledge walkthrough: holger-build-thing-for-idiots.md.

The holger build target is dwarves' CI/CD pipeline that builds holger's three deployment executables — the tiers embedded · mini · full, each a distinctly-named binary (holger-embedded / holger-mikro / holger-full) built from holger's one holger-server-cli source tree by a mutually-exclusive fatness feature. This is the build-thing that "builds all 3 holger executables", moved out of nornir's holger notion into the forge where a CI/CD target belongs.

The division of labour — two brains, one toolbox (Law #5 / #5a)

holger already declares its build-space as data (holger-build-space crate + .nornir/build-variants.toml, the first consumer of nornir-build-thing). The holger build target is the other half of that arc: the forge that consumes that declaration and builds every tier.

The system as one — the function map (f0)

part lives in what it is
f1 pipeline-as-data crates/dwarves/src/holger_build.rs pipeline() a brokkr::Pipeline: one build stage, one RunKind::Variant(tier) step per tier; each publishes its tier binary as an artifact
f2 plan/wiring resolve crates/dwarves/src/brokkr/resolve.rs resolve_variants maps every Variant step onto a target in a BuildVariantSet; VariantResolution reports resolved + missing; is_complete() iff all resolve
f3 run-time build seam crates/dwarves/src/runner.rs RealRunner → nornir_build_thing::build_variant the heavy half: discovers holger's set, cargo builds each tier, captures provenance
f4 local CLI verb crates/dwarves/src/main.rs dwarves holger-build <path> resolves the 3 tiers against a LOCAL holger .nornir/build-variants.toml; exit 0 iff all resolve; does NOT compile holger
f5 server RPC crates/dwarves/src/server.rs dwarf.v1 ResolveHolgerBuild the SAME resolution over the wire: HolgerBuildRequest{holger_root} → HolgerBuildReply{tiers[], resolved, missing, complete, found}; per-tier bin·package·cargo argv. Registered on the shared nornir-service serve loop + bearer interceptor (no second server); compile-free
f6 thin-client verb crates/dwarves/src/thin_client.rs resolve_holger_build + dwarves holger-build --server <addr> drives the f5 RPC over a REAL gRPC round-trip (the path is resolved on the SERVER); prints the same 3-tier report + exit code as f4. Reuses the ONE shared thin_client::call connect+bearer helper (no per-verb tonic client — Law #5)

Why resolve, not just build

A Variant step only fails on an unknown target at run time, inside build_variant. resolve_variants is the front-door check that lifts that to plan time: it answers "does the holger build target still wire onto holger's declared build-space?" without compiling holger — the affordable CI assertion. If holger renames or drops a tier, the plan reports it missing and is_complete() flips false (the RED-when-broken guard). The tier names here (embedded/mini/full) are holger's real declared ones, so a live resolve_against_repo over the sibling checkout resolves identically to the fixture the test uses.

Three doors onto one resolution (f4 · f5 · f6)

The holger build target now has three doors, one resolve: the local CLI verb (f4, in-process against a local checkout), the server RPC (f5, the wire surface), and the thin-client verb (f6) — dwarves holger-build --server <addr>, which routes f4's glue through f5 over a genuine gRPC round-trip. f6 is what makes the target drivable remotely end-to-end — a client on machine A resolves holger's tiers against a dwarves-server on machine B — not merely testable via the handler.

The client side is the shared dwarves::thin_client module: call(url, token, workspace, f) is the ONE connect+bearer helper EVERY --server verb reuses (the client half of nornir_service's bearer contract — authorization: Bearer <token>), lifted into the lib so the exact path the verb runs is reachable from a live-server round-trip test (no per-verb hand-rolled tonic client — Law #5). resolve_holger_build is the one-line RPC wrapper; main.rs's thin_holger_build is just print + exit-code glue, byte-identical in shape to f4. The path argument is resolved on the SERVER's filesystem; an empty request ⇒ the server's $DWARVES_HOLGER_REPO/../holger default.

Remote-driven — one resolution, two doors (f5)

The north-star is that every surface is remote-controllable. The dwarf.v1 ResolveHolgerBuild RPC is the CLI verb's wire twin: it calls the SAME holger_build::resolve_against_repo_opt (no twin — Law #5) and returns the 3-tier resolution as data — one HolgerTier row per tier (name · step · resolved · bin · package · materialized cargo argv) plus resolved/missing counts, complete, and found. complete is the RED-when-broken predicate: a dropped/renamed tier comes back resolved=false and flips it. A checkout with no build-space returns found=false (an empty plan, not a 404 — mirroring the CLI's exit-2); a malformed descriptor is InvalidArgument. The handler is registered through the shared nornir-service serve loop + bearer-auth interceptor — no second server, no hand-rolled tonic bootstrap (Law #5). Still compile-free: the RPC never builds holger (a remote dwarves run --real over holger is the run-time path).

What stays out (the leaf/conductor line)

The actual cargo build, the provenance record, the BuildVariantSet type — all nornir-build-thing's (the reusable leaf). dwarves keeps only the target: the pipeline, its resolution against a declared set, and the CLI/run surface. The forge plans and wires; the build-thing builds.