Runner
A non-Windows platform, silently ā there is nothing to stage. #| #| =item Windows, with no pins recorded yet: the bundle is built with #| its
.cmdand.ps1launchers alone and a loud one-off notice #| explains why. That is the bootstrap state, and it ends the moment a #| runner release is published and its checksums are committed. method stage( IO() :$bundle-dir!, Str:D :$slug!, Str:D :$exec!, IO() :$cache-dir = self.cache-dir, IO() :$pins-path, :&download = &http-download, --> Hash ) { return %() unless self.arch-for($slug).defined;
NAME
App::Ariza::Runner - the compiled launcher a Windows bundle starts from
SYNOPSIS
use App::Ariza::Runner;
say App::Ariza::Runner.artifact-name('windows-arm64');
# ariza-runner-windows-aarch64.exe
say App::Ariza::Runner.tag; # runner-v1
say App::Ariza::Runner.pins.keys; # the artefacts pinned
# What App::Ariza::Launcher does for a Windows bundle:
my %r = App::Ariza::Runner.stage(
:bundle-dir($work), :slug<windows-x86_64>, :exec<moneymoor>);
say %r ?? "{%r<path>} ({%r<sha256>})" !! 'no runner pinned yet ā scripts only';
DESCRIPTION
A Windows bundle's documented entry point is < bin/<exec>.exe >: a
small C program, in this repository's runner/ directory, that reads
< bin/<exec>.ariza > beside itself, exports the same environment the
.cmd launcher exports, and starts the bundled interpreter with the
caller's arguments unchanged.
This module is the build-time half of that: which artefact a platform gets, where it is published, and the verification a downloaded executable has to pass before it is allowed anywhere near a bundle.
Why a fetched binary rather than a compiled one
Compiling the runner during ariza bundle would put a C toolchain in
the bundling path ā on every machine, for every cross-build ā to produce
a file that is identical for every app. So it is built once per release
by CI, on the toolchains that build everything else Windows in this
ecosystem (MSYS2 UCRT64 for x86_64, CLANGARM64 for aarch64), published
as a release artefact, and pinned by digest here. A bundle carries a
byte-identical, hash-verified copy of a binary anyone can rebuild from
runner/ and compare.
The bootstrap ladder
resources/runner-checksums.txt starts empty, because the code that
downloads a runner has to exist before the release it downloads can be
published. So:
No pins recorded. A Windows bundle is built without the executable ā the
.cmdand.ps1launchers alone, exactly the output ariza produced before the runner existed ā and the build says so once, loudly, naming the file to fill in.Any pin recorded. The ladder inverts. A missing entry for the target architecture, a failed download, or a digest mismatch fails the build. Past that point a bundle without a verified runner is a regression rather than a stage of bootstrapping, and shipping one quietly would be the worst of both.
There is deliberately no third rung, no --no-runner and no
--skip-verify: the two states above are the only two that are ever
true, and an unverified executable staged into a bundle is not a
degraded build, it is a different piece of software.
METHODS
stage(:$bundle-dir!, :$slug!, :$exec!, :$cache-dir, :$pins-path, :&download --> Hash)
Put the runner at < <bundle>/bin/<exec>.exe > and return
{ path, artifact, tag, url, sha256 }. Returns an empty hash for a
non-Windows platform (nothing to stage) and for the bootstrap state
above (nothing pinned yet), so if %r { ... } is the whole test.
The extra fields are there because ariza-manifest.json records every
downloaded component with its source URL and its verified digest, and
the runner is a downloaded component ā the one binary in a bundle a
reader could otherwise not trace back to a published artefact.
:$pins-path reads an alternate pin file, which is what lets a test
exercise both rungs of the ladder ā and every way the upper one fails ā
against the same code the shipped resource goes through.
fetch(:$slug!, :$cache-dir, :%pins, :$tag, :&download --> IO::Path)
The cached, digest-verified artefact for a slug, downloading it if this
machine has not got it. A cached copy that fails its pin is deleted and
re-fetched; a fresh download that fails its pin is deleted and the build
stops. :&download is the same seam App::Ariza::Rakudo takes, so
the whole path is testable without a network.
pins(IO() $path --> Hash)
< artefact => sha256 > from resources/runner-checksums.txt.
Comments and blank lines are ignored; anything else must be a
< <64 hex> <filename> > entry, and a line that is not dies naming
the file and the line number.
tag(--> Str) / url(:$slug!, :$tag --> Str) / cache-dir(--> IO::Path)
The release tag from resources/RUNNER_VERSION, the download URL built
from it, and $XDG_CACHE_HOME/ariza/runner (keyed by tag inside, so
two tags never share a file).
arch-for(Str $slug --> Str) / artifact-name(Str $slug --> Str)
windows-x86_64 is x86_64 and windows-arm64 is aarch64;
everything else is the undefined Str, which is how "this platform has
no runner" is spelled everywhere in this module.
update-handoff-capable(Mu $tag --> Bool)
True only for an exact runner-vN tag whose numeric N is at least 2.
runner-v2 is the first native launcher that can create, validate and honor
the authenticated managed-update handoff; an update-enabled Windows build
must not infer capability merely because some executable was staged.
SEE ALSO
App::Ariza::Launcher, which calls this and writes the sidecar the runner reads.
AUTHOR
Matt Doughty
COPYRIGHT AND LICENSE
Copyright 2026 Matt Doughty
This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.