Skip to content

hwledger-release

Role. Owns the macOS v1 release pipeline: Sparkle appcast XML, DMG creation, codesign, notarization, XCFramework assembly, and keyframe extraction for changelogs.

Why this crate

The first cut of the release pipeline was a mix of shell scripts and Python glue. That was fragile (bash quoting bugs), untested, and slow to iterate. Rewriting it as a Rust crate means the release path runs the same way locally and in CI, errors are typed, and each stage is independently testable.

ADR-0006 established the distribution model. ADR-0008 deferred parts of the pipeline pending an Apple Developer account; the crate is scoped to ship the stages that do not require paid Apple credentials and to stub the rest.

Rejected: keep the shell+Python path. Rejected explicitly in commit 82ca91f feat(hwledger-release): Rust-based release pipeline replaces shell+Python.

Belongs here: release orchestration, subprocess wrappers for codesign/xcrun notarytool, DMG layout, appcast generation, keyframe extraction. Does not belong here: docsite builds, CI workflow YAML, GUI binaries.

Public API surface

ModulePurposeStability
appcastSparkle appcast.xml generationstable
bundle.app bundle assemblystable
dmgDMG creation + background + layoutstable
notarizexcrun notarytool wrapperstable (stubbed per ADR-0008)
xcframeworkMulti-arch FFI framework bundlingstable
recordJourney recording driverstable
keyframesffmpeg-driven keyframe extractionstable
subprocessTyped Command wrapperstable
ReleaseError, ReleaseResultstable

When to reach for it

  1. Cutting a releasecargo run -p hwledger-release -- cut --version v0.2.0.
  2. Regenerating the Sparkle appcast after a hotfix.
  3. Producing keyframe thumbnails for docsite changelogs from a recorded VHS tape.

Evolution

SHANote
82ca91fInitial: feat(hwledger-release): Rust-based release pipeline replaces shell+Python
4e47ef5feat(hwledger-release): Rust-based release pipeline replaces shell+Python (follow-up hardening)
fffba1afeat(big-batch): real tapes + GUI recorder + 2026 freshness pass + release crate + deep coverage + appdriver + LaTeX fix — crate integrated into the big-batch workflow

Size. 975 LOC, 6 tests. Low test count reflects that most logic is subprocess glue; the trust boundary is Apple's tools, not our wrappers.

Design notes

  • subprocess wrapper captures stdout/stderr and surfaces non-zero exits as typed errors — no silent "it worked" on a failed codesign.
  • Notarization path intentionally fails loudly when credentials are missing; that is the failure the project wants, per repo-wide "no silent graceful degradation" policy.
  • Appcast XML is generated from a typed model so malformed XML is a compile error, not a runtime 500.

Released under the Apache 2.0 License.