Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ccb0c1b
fix(doctor): the commit path becomes a checked precondition
wenzowski Sep 8, 2026
591e5c2
fix(config): declare the commit gate as a startup precondition
wenzowski Sep 8, 2026
fda712f
fix(doctor): the commit-gate predicate is a sub-verb, not a report row
wenzowski Sep 8, 2026
05bc3c5
fix(doctor): leave the governed shell task alone
wenzowski Sep 8, 2026
dd0321a
fix(doctor): the exec-bit reading is unix's, so the case that asserts…
wenzowski Sep 8, 2026
74eac37
fix(doctor): state the Windows hook contract instead of gating the ca…
wenzowski Sep 8, 2026
bf1032a
fix(doctor): declare the new verb's exit set
wenzowski Sep 8, 2026
3eaf24f
fix(doctor): drop the exit-set declaration, written against a borrowe…
wenzowski Sep 8, 2026
934a34b
fix(session): install the release at session start, never a compile
wenzowski Sep 8, 2026
c7fdac4
fix(session): spell the identity fallback on one line
wenzowski Sep 8, 2026
58fb590
fix(install): replace the binary atomically, because it may be running
wenzowski Sep 8, 2026
3824a8d
fix(land): stop giving up on a healthy fleet, and correct the contract
wenzowski Sep 8, 2026
7685b8e
fix(session): the identity guard must try, not merely test presence
wenzowski Sep 8, 2026
0a96d6e
fix(land): describe the engine's loop, not the retired shell task's
wenzowski Sep 8, 2026
0be5406
fix(ci): give the x64 `ci-` family a warm writer, and gate the orphaning
wenzowski Sep 8, 2026
9ea7750
fix(ci): pin the mise `mise-action` installs to the version the tree …
wenzowski Sep 8, 2026
ce19e1e
fix(ci): pin mise in the remaining required-check and scheduled workf…
wenzowski Sep 8, 2026
72595b0
fix(ci): pin mise in the last thirteen workflows, completing the sweep
wenzowski Sep 8, 2026
e915959
fix(policy): gate the mise pin against the version workflows install
wenzowski Sep 8, 2026
1e61fec
docs(preset)!: the module header says scope is per module now
wenzowski Sep 8, 2026
857d59f
fix(preset): the manifest census reads a module's named fields
wenzowski Sep 8, 2026
2a4a02a
fix(preset): write the action as a coordinate, not a bare vendor name
wenzowski Sep 8, 2026
d6cee27
fix(policy): a range move is not a landing lap
wenzowski Sep 8, 2026
2ce05b8
fix(rules): classify `unless_contains` in the column census
wenzowski Sep 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/arch-probe.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5 (CLOUD-404 retry fix, now a release)
with:
# Pinned to `batten.toml`'s `[[provision]]` version (CLOUD-1672), and
# here the pin is load-bearing for the EXPERIMENT rather than only for
# the install: this probe's validity rests on both arms differing only
# in `runs-on`, so an unpinned mise lets the two arms install different
# toolchains and destroys the comparison silently.
version: 2026.9.1
# Only what the build needs. This job runs no gate, so the `ci` job's
# wide list would be paying install time on both arms for tools
# nothing here invokes — and install time is exactly the term the
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/auto-bot-land.yml
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,11 @@ jobs:
with:
persist-credentials: false
- uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5 (CLOUD-404 retry fix, now a release)
with:
# Pinned to `batten.toml`'s `[[provision]]` version (CLOUD-1672). The
# digest above pins the ACTION; this pins the MISE it installs, which
# is a separate resolution the digest does not reach.
version: 2026.9.1
if: steps.target.outputs.num != ''
# THE LANE NEEDS THE ENGINE NOW, AND NOTHING WAS PROVIDING IT (CLOUD-1143's
# consequence). `checks-green` was retired onto the engine, so `mise.toml`'s
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/auto-release-land.yml
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,11 @@ jobs:
with:
persist-credentials: false
- uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5 (CLOUD-404 retry fix, now a release)
with:
# Pinned to `batten.toml`'s `[[provision]]` version (CLOUD-1672). The
# digest above pins the ACTION; this pins the MISE it installs, which
# is a separate resolution the digest does not reach.
version: 2026.9.1
if: steps.target.outputs.num != ''
# THE LANE NEEDS THE ENGINE NOW, AND NOTHING WAS PROVIDING IT (CLOUD-1143's
# consequence). `checks-green` was retired onto the engine, so `mise.toml`'s
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/branch-hygiene.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ jobs:
persist-credentials: false
- uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5 (CLOUD-404 retry fix, now a release)
with:
# Pinned to `batten.toml`'s `[[provision]]` version (CLOUD-1672). The
# digest above pins the ACTION; this pins the MISE it installs, which
# is a separate resolution the digest does not reach.
version: 2026.9.1
# `gh` for both readings, `jq` for the GraphQL projection. Narrow, for
# the reason ci.yml states: the whole toolchain is ~10s a job that
# this one has no use for.
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/ci-drift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ jobs:
with:
persist-credentials: false
- uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5 (CLOUD-404 retry fix, now a release)
with:
# Pinned to `batten.toml`'s `[[provision]]` version (CLOUD-1672). The
# digest above pins the ACTION; this pins the MISE it installs, which
# is a separate resolution the digest does not reach.
version: 2026.9.1
# THE FETCH, one step before the gate. It lives here rather than in a
# `mise-tasks/` program because a credentialed read is the one thing the
# engine may not do (house-style §5), and this is where the job token
Expand Down
130 changes: 102 additions & 28 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,20 @@ jobs:
fi
- uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5 (CLOUD-404 retry fix, now a release)
with:
# PINNED TO `batten.toml`'s `[[provision]]` ROW, NOT LEFT TO RESOLVE
# (CLOUD-1672). The action digest above pins the ACTION; this pins the
# MISE it installs, which is a separate resolution the digest does not
# reach. Unset, it takes whatever is newest when the job starts —
# measured 2026-09-08, that was v2026.9.3, whose linux-x64 asset 404s,
# and every job in every workflow died at this step inside 11 seconds.
# v0.0.152 published with zero binaries as a result.
#
# The provision row's own comment already names this harm one layer
# down: a runner that updates itself under a container makes two
# sessions on one commit run different toolchains. The pin existed and
# this layer could not see it, so the tree declared one version and CI
# ran another. `ci-tools-check` now refuses any drift between the two.
version: 2026.9.1
# Install only what this job's gates actually invoke, not the whole
# 18-tool dev set. Every job used to install everything, and `zig`
# (17.3s) finished last, so zig alone set the install wall clock in
Expand Down Expand Up @@ -640,24 +654,34 @@ jobs:
# that was supposed to make this a finding rather than a surprise does not
# reach it. That asymmetry is the row's to close, not this job's.
#
# COLD, AND THE JUSTIFICATION FOR THAT IS NOW FALSE. `cache-warm-linux`
# writes `ci-` on arm64, so no warm x64 entry exists for this job and it pays
# a full build every run.
# WARM SINCE CLOUD-1477, AND THE TWO PRICINGS BEFORE IT WERE BOTH WRONG.
#
# The first priced this job's cold build as free: "a job running in parallel
# with a 1730s pole has ~1200s of slack." True when written, and falsified by
# this repository's own change — CLOUD-1410 removed the pole. Measured on run
# 33845451921, the first warm arm64 run of a real `crates/**` change: `ci`
# 364s, `bats` 271s, and THIS JOB 683s, 1.9x the next longest and the critical
# path of the whole workflow.
#
# This comment used to price that as free: "a job running in parallel with a
# 1730s pole has ~1200s of slack." The premise was true when it was written
# and this repository's own change falsified it. Measured on run 33845451921,
# the first warm arm64 run of a real `crates/**` change: `ci` 364s, `bats`
# 271s, and THIS JOB 683s — 1.9x the next longest, and the critical path of
# the whole workflow. There is no 1730s pole to hide behind any more, because
# CLOUD-1410 removed it. The slack is gone and this job is the pole.
# The second declined the fix on a ceiling: buying a warm x64 entry needs a
# second warm writer, "doubling the cache families against a store measured at
# 10.72 GiB over a 10 GiB ceiling", so the answer was said to be CLOUD-1431 or
# a revert of the family to x64. Every term of that is now spent.
# `cache-sweep.yml` (CLOUD-1453, released v0.0.142) took the store to 3.16 GiB
# by evicting merged pull requests' entries, so the ceiling is not the binding
# constraint. CLOUD-1431 is Done and landed a GATE over the
# release-target/provision-platform pairing rather than an arm64 scanner, so
# this job still cannot move. And eviction bought 12% and not a hit: 683s to
# 600s across jobs 100903936005 and 101280975479, which is pressure lifting
# rather than a restore landing.
#
# What has not changed is the trade that was declined: buying a warm x64
# entry needs a second warm writer, doubling the cache families against a
# store measured at 10.72 GiB over a 10 GiB ceiling. So the answer is not a
# second writer — it is CLOUD-1431, which removes the reason this job is
# stranded here at all, or a revert of the family to x64 if `arch-probe.yml`
# shows arm64 buys nothing.
# So the second writer is what landed. `cache-warm-linux-x64` in
# `release-plz.yml` writes `ci-` on x64 for this job, exactly as
# `cache-warm-linux` writes it on arm64 for `ci`, `bats` and `commit-lint`,
# and `read-family-has-a-warm-writer` refuses the arrangement where a
# read-only consumer has no writer on its own architecture — so the orphaning
# that produced this comment's whole history is now a finding rather than a
# green run that took longer.
runs-on: ubuntu-latest
# DERIVED RATHER THAN OBSERVED, because this job has no history yet. The
# terms: 189.6s for the step itself (job 100792703868), plus this job's own
Expand Down Expand Up @@ -735,6 +759,20 @@ jobs:
# is recorded there rather than papered over with a step that never fixed it.
- uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5 (CLOUD-404 retry fix, now a release)
with:
# PINNED TO `batten.toml`'s `[[provision]]` ROW, NOT LEFT TO RESOLVE
# (CLOUD-1672). The action digest above pins the ACTION; this pins the
# MISE it installs, which is a separate resolution the digest does not
# reach. Unset, it takes whatever is newest when the job starts —
# measured 2026-09-08, that was v2026.9.3, whose linux-x64 asset 404s,
# and every job in every workflow died at this step inside 11 seconds.
# v0.0.152 published with zero binaries as a result.
#
# The provision row's own comment already names this harm one layer
# down: a runner that updates itself under a container makes two
# sessions on one commit run different toolchains. The pin existed and
# this layer could not see it, so the tree declared one version and CI
# ran another. `ci-tools-check` now refuses any drift between the two.
version: 2026.9.1
# THE `ci` JOB'S LIST, NOT A NARROWER ONE, and the width is decided by
# what `enforce` reaches rather than by what this job looks like it
# needs. `batten.toml`'s `command` rules shell out to `hk`, to `regal`
Expand All @@ -753,22 +791,30 @@ jobs:
with:
path: ~/.pkl/cache
key: pkl-${{ runner.os }}-${{ hashFiles('hk.pkl') }}
# THE `ci-` FAMILY, AND THE ONLY STEP IN THIS WORKFLOW THAT STILL WRITES
# ONE. That is the rule the `ci`, `bats` and `windows` steps are stated
# over, applied rather than excepted: `save-if: false` belongs on a reader
# of a family a trunk-side job WARMS, and is wrong where no warm writer
# exists, because a pure consumer of an empty family has nothing at all.
# `cache-warm-linux` writes `ci-` on arm64 (see this job's `runs-on` for
# why this one cannot follow it), so on x64 that family has no writer.
# THE `ci-` FAMILY, READ-ONLY LIKE EVERY OTHER PULL-REQUEST CONSUMER OF IT
# (CLOUD-1477). This step was this workflow's last writer, and the reason it
# was one has been removed rather than merely overruled.
#
# The rule is the one the `ci`, `bats` and `windows` steps are stated over:
# `save-if: false` belongs on a reader of a family a trunk-side job WARMS,
# and is wrong where no warm writer exists, because a pure consumer of an
# empty family has nothing at all. That exception applied here for as long
# as `cache-warm-linux` wrote `ci-` on arm64 alone; `cache-warm-linux-x64`
# now writes it on x64, so this job is an ordinary consumer and the
# exception is spent.
#
# It is not useless. A cache read is scoped to the run's own ref plus the
# base branch, so what this cannot do is serve ANOTHER pull request — but
# it does serve the next lap of THIS one, and `land` re-runs CI once per
# lap on a fresh SHA under the same `refs/pull/N/merge` ref. A landing loop
# is exactly where the repeat reads are.
# WHAT THE WRITE WAS BUYING, AND WHY IT IS NOT WORTH KEEPING BESIDE A WARM
# WRITER. A cache read is scoped to the run's own ref plus the base branch,
# so the entry could never serve another pull request — only the next lap of
# this one, under the same `refs/pull/N/merge` ref that `land` re-runs on.
# Against a warm x64 entry the first lap now restores instead of building,
# so the later laps have nothing left to inherit that they would not already
# get; what the write still costs is a multi-gigabyte upload per lap into
# the 10 GiB store that `cache-sweep.yml` then has to reclaim.
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
shared-key: ci-
save-if: false
- run: mise run batten-check
env:
# `batten-check` reaches `doctor` through the same chain the `ci` job
Expand Down Expand Up @@ -868,6 +914,20 @@ jobs:
run: git fetch origin main:refs/remotes/origin/main
- uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5 (CLOUD-404 retry fix, now a release)
with:
# PINNED TO `batten.toml`'s `[[provision]]` ROW, NOT LEFT TO RESOLVE
# (CLOUD-1672). The action digest above pins the ACTION; this pins the
# MISE it installs, which is a separate resolution the digest does not
# reach. Unset, it takes whatever is newest when the job starts —
# measured 2026-09-08, that was v2026.9.3, whose linux-x64 asset 404s,
# and every job in every workflow died at this step inside 11 seconds.
# v0.0.152 published with zero binaries as a result.
#
# The provision row's own comment already names this harm one layer
# down: a runner that updates itself under a container makes two
# sessions on one commit run different toolchains. The pin existed and
# this layer could not see it, so the tree declared one version and CI
# ran another. `ci-tools-check` now refuses any drift between the two.
version: 2026.9.1
# One line, for the reason the `ci` job's list states: `ci-tools-check`
# parses these as a scalar and several names begin with `aqua:`, which
# a block scalar's continuation lines read as new keys.
Expand Down Expand Up @@ -1033,6 +1093,20 @@ jobs:
fetch-depth: 0
- uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5 (CLOUD-404 retry fix, now a release)
with:
# PINNED TO `batten.toml`'s `[[provision]]` ROW, NOT LEFT TO RESOLVE
# (CLOUD-1672). The action digest above pins the ACTION; this pins the
# MISE it installs, which is a separate resolution the digest does not
# reach. Unset, it takes whatever is newest when the job starts —
# measured 2026-09-08, that was v2026.9.3, whose linux-x64 asset 404s,
# and every job in every workflow died at this step inside 11 seconds.
# v0.0.152 published with zero binaries as a result.
#
# The provision row's own comment already names this harm one layer
# down: a runner that updates itself under a container makes two
# sessions on one commit run different toolchains. The pin existed and
# this layer could not see it, so the tree declared one version and CI
# ran another. `ci-tools-check` now refuses any drift between the two.
version: 2026.9.1
# rust builds the two binaries under measurement, hyperfine samples
# them, jq reads the ratio out. See the ci job for why these lists are
# narrow.
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/commit-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ jobs:
fetch-depth: 0
- uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5 (CLOUD-404 retry fix, now a release)
with:
# Pinned to `batten.toml`'s `[[provision]]` version (CLOUD-1672). The
# digest above pins the ACTION; this pins the MISE it installs, which
# is a separate resolution the digest does not reach.
version: 2026.9.1
# `rust`, and nothing else. `commit-lint` depends on `commit-check` and
# `commit-attribution`, both of which are `cargo run --quiet -p batten`,
# and on `signing-posture`, which uses only git, gpg and ssh-keygen —
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ jobs:
persist-credentials: false
- uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5 (CLOUD-404 retry fix, now a release)
with:
# Pinned to `batten.toml`'s `[[provision]]` version (CLOUD-1672). The
# digest above pins the ACTION; this pins the MISE it installs, which
# is a separate resolution the digest does not reach.
version: 2026.9.1
# cargo-llvm-cov drives cargo; rust supplies the compiler and the
# rustup that fetches llvm-tools-preview. Nothing else is invoked.
# `mise run ci-tools-check` fails if a name here drifts from mise.toml.
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/fast-forward.yml
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@ jobs:
persist-credentials: false
- uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5
with:
# Pinned to `batten.toml`'s `[[provision]]` version (CLOUD-1672). The
# digest above pins the ACTION; this pins the MISE it installs, which
# is a separate resolution the digest does not reach.
version: 2026.9.1
# The roster lives in `mise.toml`'s `[env]`, read from there by
# `checks-green` and by `land`'s `graded_runs` alike (CLOUD-327). No
# `[tools]` entry is needed to evaluate it, so none is installed.
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/fuzz.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ jobs:
persist-credentials: false
- uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5 (CLOUD-404 retry fix, now a release)
with:
# Pinned to `batten.toml`'s `[[provision]]` version (CLOUD-1672). The
# digest above pins the ACTION; this pins the MISE it installs, which
# is a separate resolution the digest does not reach.
version: 2026.9.1
# `rust` alone: it supplies cargo and the rustup that `mise run fuzz`
# uses to fetch the nightly libFuzzer's `-Z sanitizer` requires, and
# to build the pinned cargo-fuzz under it. cargo-fuzz is deliberately
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/hook-latency-drift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ jobs:
with:
persist-credentials: false
- uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5 (CLOUD-404 retry fix, now a release)
with:
# Pinned to `batten.toml`'s `[[provision]]` version (CLOUD-1672). This
# job measures the gate's own latency on a clock, so an unpinned
# toolchain changes what the series measures rather than failing.
version: 2026.9.1
- name: Report a fast tier that no longer matches its budget
shell: bash
env:
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/land-divergence.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ jobs:
with:
persist-credentials: false
- uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5 (CLOUD-404 retry fix, now a release)
with:
# Pinned to `batten.toml`'s `[[provision]]` version (CLOUD-1672). The
# digest above pins the ACTION; this pins the MISE it installs, which
# is a separate resolution the digest does not reach.
version: 2026.9.1
# Measure to a FILE, then read it back — never `measure | assert`. A
# pipeline hands the step's exit status to its last stage, so a measurement
# that died would be judged as a clean empty window rather than reported
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/lock-currency.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ jobs:
with:
persist-credentials: false
- uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5 (CLOUD-404 retry fix, now a release)
with:
# Pinned to `batten.toml`'s `[[provision]]` version (CLOUD-1672). This
# is the clock that bumps pins, so leaving it resolving latest means
# the job that MOVES a pin is the one a bad upstream release stops.
version: 2026.9.1
# The lockfile rewrite this performs is fine here and only here: the
# checkout is disposable, and no commit is being judged by it.
- run: mise run lock-check
Loading
Loading