Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
694886d
fix(checks): a run that completed without judging cannot erase a verdict
wenzowski Sep 9, 2026
d336a60
fix(mutate): the sweep owns its suite bound, and the row that proves it
wenzowski Sep 9, 2026
89f8ebf
docs(rules): a verdict question is answered by running the gate, not …
wenzowski Sep 9, 2026
16a1bdc
fix(core): keep the consumer's artifact names out of the core's comments
wenzowski Sep 9, 2026
4bed544
docs(rules): a gate's exit code answers the GATE's question, not alwa…
wenzowski Sep 9, 2026
16a7a21
docs(rules): decider-vs-floor is a property of the PAIR, not of the gate
wenzowski Sep 9, 2026
6cd5993
docs(rules): the lede said three questions over a five-row table
wenzowski Sep 9, 2026
b72ded4
perf(mcp): reduce `get_document`, which emitted more than it stored
wenzowski Sep 9, 2026
2f26d8c
perf(tests): split the record replay per trial block and build its re…
wenzowski Sep 9, 2026
25c17db
perf(tests): replay the record gate in-process instead of over 78 spawns
wenzowski Sep 9, 2026
74a1bd5
perf(ci): warm the `cross-` cache family and stop its reader writing
wenzowski Sep 9, 2026
de00501
fix(tests): the hoisted vocabulary is already a reference
wenzowski Sep 9, 2026
2eeb294
perf(ci): warm the darwin-link cache family and stop its reader writing
wenzowski Sep 9, 2026
c4f0305
fix(ci): the warm job spells its key as the reader spells it, not as …
wenzowski Sep 9, 2026
cc3c21f
perf(ci): a scheduled trunk writer warms a family, and `perf-` always…
wenzowski Sep 9, 2026
f12ee42
docs(hk): the slow tier is nine steps, and the comment said six
wenzowski Sep 9, 2026
1adb344
perf(mutate): the runner's bound is a sleep it never reaps on a red case
wenzowski Sep 9, 2026
2aee43b
fix(mutate): the watchdog signalled a group it did not own
wenzowski Sep 9, 2026
5ff1dd8
fix(mutate): the bound blocks on a channel, so no delay waiver is needed
wenzowski Sep 9, 2026
3f88573
fix(checks-green): the winner is a function of the set, not the slice…
wenzowski Sep 9, 2026
9751f66
feat(run-shape): every mise call is backgrounded, and a backgrounded …
wenzowski Sep 9, 2026
ec32a76
chore(claude): the classifier stops refusing this repo's own lifecycl…
wenzowski Sep 9, 2026
cd28fe1
fix(run-shape): exercise both new predicates, and stop asserting a fo…
wenzowski Sep 9, 2026
ce4020a
perf(hooks): the commit gate calls the binary, because a git hook is …
wenzowski Sep 9, 2026
5d7e374
docs(agents): name PR-activity subscription in the heartbeat ban, so …
wenzowski Sep 9, 2026
792665c
fix(tests): move the live-root mise cases to the backgrounded form, a…
wenzowski Sep 9, 2026
a1faea2
revert(hooks): the commit-msg steps stay on the task, because respell…
wenzowski Sep 9, 2026
4f54f99
fix(pipeline-shapes): move the prescribed form to backgrounded-and-un…
wenzowski Sep 9, 2026
21329c9
fix(verdict): the discard family stops prescribing the form backgroun…
wenzowski Sep 9, 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
14 changes: 14 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,15 @@
}
]
},
"autoMode": {
"allow": [
"$defaults",
"Button lifecycle commands are normal work in this repository and are allowed, including inside compounds and with heredocs: `mise run <task>`, `mise exec -- cargo ...`, `cargo` directly, `hk check`, and `batten <verb>` — among them `override request`/`override spend`, `claim check`, `check`, `enforce`, `policy`, `config`, `receipt`, `commit check`, `attribution check` and `mutate`.",
"Writing a commit message or an admission answer to the session scratchpad (python3/cat/printf into a heredoc or file) and then feeding it to `git commit -F <file>` or `batten override request < <file>` is the DECLARED route for those gates, not an attempt to evade one: `run-shape`'s `commit write missing` and `commit bind missing` refuse every other spelling.",
"A compound that combines a scratch-file write with `git add` and `git commit`, or that chains a `batten`/`mise` gate with the command it gates, is one lifecycle step rather than unrelated actions.",
"`git commit` and `git push` to the session's own feature branch are ordinary steps here: AGENTS.md makes carrying a change through to landed-and-verified the default and the gates, not a prompt, are what stop it."
]
},
"permissions": {
"allow": [
"Edit",
Expand All @@ -104,6 +113,11 @@
"Bash(batten:*)",
"Bash(cp:*)",
"Bash(mkdir:*)",
"Bash(cargo:*)",
"Bash(mise exec:*)",
"Bash(python3:*)",
"Bash(hk:*)",
"Bash(jq:*)",
"mcp__serena",
"mcp__serena__delete_memory",
"mcp__serena__edit_memory",
Expand Down
15 changes: 15 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,21 @@ jobs:
with:
# The profile is part of the key — see the `ci` job above.
shared-key: perf-
# READ-ONLY, because `perf.yml`'s own job is this family's writer and
# always was. It runs daily on a schedule, `runs-on: ubuntu-latest`, and
# takes this exact `shared-key` — same key, same architecture — so its
# entry sits on `refs/heads/main` and every pull request can read it.
# This job was nonetheless writing a full `--release` target directory
# on top of that, scoped to `refs/pull/N/merge` where nothing else can
# reach it: the largest single entry any reader here produces, for the
# profile no other job builds.
#
# `ci-cache-declared` could not see the writer until this change,
# because its `warmed` set counted `push` triggers only. That bound is
# now `trunk_writer` — push OR schedule — for the reason recorded in the
# module: what a pull request can read follows the writing run's REF,
# and a scheduled run on `main` has the same ref a pushed one does.
save-if: false
# CLOUD-1331, corrected by CLOUD-1342. The BASE arm is a pure function of
# the merge-base SHA, the pinned toolchain and `[profile.release]`, and
# `main` advances only by fast-forward to already-judged SHAs — so
Expand Down
128 changes: 128 additions & 0 deletions .github/workflows/release-plz.yml
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,134 @@ jobs:
- run: mise exec -- cargo nextest run --no-run --workspace
if: steps.rust-cache.outputs.cache-hit != 'true'

# THE TWO ORPHANED FAMILIES ON THE PULL-REQUEST PATH (CLOUD-1477's siblings).
#
# `ci-` has had warm writers since CLOUD-1416/1477 and `windows-` since the job
# below. `cross-` and `semver-` had none, and both are REQUIRED checks — so every
# pull request cold-built them AND uploaded a multi-hundred-MB entry scoped to
# `refs/pull/N/merge` that no other pull request can read. That write is the
# store pressure `cache-sweep.yml` exists to reclaim rather than a saving:
# CLOUD-1453 measured 10.77 GiB against a 10 GiB ceiling with 81% of it four
# already-merged PRs. Their readers now carry `save-if: false`, so these two jobs
# are what makes the families readable at all.
#
# ONE JOB PER FAMILY, NOT A SHARED ENTRY, and `rust.yml`'s matrix block already
# records why: a second leg restoring a shared entry thrashes it. `cross` builds
# a windows-gnu target and `semver` a base-revision closure; neither is the `ci-`
# host artifact set, so pointing them at `ci-` would trade a cold build for a
# thrashed one.
#
# x64 FOR THE READERS' REASON, NOT BY DEFAULT. rust-cache puts
# `runnerOS-runnerArch` inside the restore prefix (`config.ts:93`, before `:133`),
# so a writer on another arch writes an entry its reader cannot see — the exact
# trap CLOUD-1416 sprang on `batten-check`. Both readers are `ubuntu-latest`
# (`rust.yml:75`, `:319`); these must move only with them.
cache-warm-cross:
name: cache-warm-cross
runs-on: ubuntu-latest
# Grandfathered for `cache-warm-linux`'s reason: no measured p95 exists for a
# job that has never run, and a guessed number would read as measured.
timeout-minutes: 30 # budget: grandfathered measured=2026-09-09
# A warm job must never be able to red the release lane, exactly as above.
continue-on-error: true
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
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
# What the `cross` job installs, for its stated reason: cross-check is
# `rustup target add` + `cargo check`, and rust is the only tool it
# touches.
install_args: rust
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
# Read by the compile step below; `ci-local-parity` property 17 holds the
# `id` and the guard together.
id: rust-cache
with:
# Must match `rust.yml`'s `cross` job exactly or this writes an entry
# that job cannot read.
shared-key: cross-
# Compile only when there is nothing to restore, as every warm job here
# does. `DOCTOR_TARGETS` must match the reader's or this fills a different
# target's artifacts.
- run: mise run cross-check
if: steps.rust-cache.outputs.cache-hit != 'true'
env:
DOCTOR_TARGETS: x86_64-pc-windows-gnu

cache-warm-darwin-link:
name: cache-warm-darwin-link
runs-on: ubuntu-latest
# THE MATRIX MIRRORS THE READER'S, AND THAT IS NOT DECORATION.
# `ci-cache-declared` resolves a family from the `shared-key` AS WRITTEN in
# the workflow, so a writer spelling the expansion (`aarch64-apple-darwin`)
# while the reader spells `${{ matrix.target }}` is two families to the gate
# and one to GitHub — measured: `read-family-has-a-warm-writer` fired on
# `rust.yml`'s `darwin-link` with this job already present. Carrying the same
# single-leg matrix makes the two keys identical as text, and keeps the
# reader's own promise that restoring a second leg is a one-word change —
# it is now one word on each side.
strategy:
fail-fast: false
matrix:
target: [aarch64-apple-darwin]
# Grandfathered for `cache-warm-linux`'s reason: no measured p95 exists for a
# job that has never run, and a guessed number would read as measured.
timeout-minutes: 30 # budget: grandfathered measured=2026-09-09
# A warm job must never be able to red the release lane, exactly as above.
continue-on-error: true
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
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
# What the `darwin-link` job installs, for its stated reason: zig
# supplies the Darwin linker, cargo-zigbuild drives cargo through it,
# and rust is the compiler.
install_args: rust zig github:rust-cross/cargo-zigbuild
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
# Read by the compile step below; `ci-local-parity` property 17 holds the
# `id` and the guard together.
id: rust-cache
with:
# SPELLED EXACTLY AS THE READER SPELLS IT — see the matrix note on
# this job. rust-cache sees the expansion either way; the gate sees
# the text, and only this spelling makes the two one family.
shared-key: ${{ matrix.target }}
# Compile only when there is nothing to restore, as every warm job here
# does. `DOCTOR_TARGETS` must match the reader's or this fills a different
# target's artifacts.
- run: mise run darwin-link ${{ matrix.target }}
if: steps.rust-cache.outputs.cache-hit != 'true'
env:
DOCTOR_TARGETS: ${{ matrix.target }}

# `semver-` IS DELIBERATELY NOT WARMED HERE, and the reason is worth recording
# so the next reader does not "finish the job". `rust.yml`'s semver block states
# that it builds RUSTDOC with a different rustc than every other job, which is
# why it holds its own key at all. A warm job running `cargo build --workspace`
# would fill that family with host artifacts the reader does not want and still
# leave the rustdoc build cold — occupying the slot with the wrong content,
# which is worse than the cold build it replaces. Warming it means running what
# the reader runs, and `mise run semver` is a COMPARISON against a base rather
# than a build, so a trunk-side warmer is a different design question.
# `cross-` has no such split: `mise run cross-check` is exactly what its reader
# runs, which is why only that one is warmed above.

cache-warm-windows:
name: cache-warm-windows
runs-on: windows-latest
Expand Down
18 changes: 18 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,13 @@ jobs:
with:
# The profile is part of the key — see `ci.yml`'s `ci` job.
shared-key: cross-
# READ-ONLY, because `cache-warm-cross` on trunk is now this family's
# writer. A PR-side write lands on `refs/pull/N/merge` and is readable
# by no other pull request, so it bought nothing and cost the store —
# CLOUD-1453 measured 81% of a 10.77 GiB store as four merged PRs'
# unreadable entries. Same posture as every warmed family's readers
# (`ci.yml:420`, `:846`, `commit-lint.yml:138`).
save-if: false
- run: mise run cross-check
env:
# Only the triple cross-check type-checks. doctor's default pair would
Expand Down Expand Up @@ -307,6 +314,17 @@ jobs:
# otherwise thrash a shared entry if the second leg is restored.
# The profile is part of the key too — see `ci.yml`'s `ci` job.
shared-key: ${{ matrix.target }}
# READ-ONLY, because `cache-warm-darwin-link` on trunk is now this
# family's writer. A PR-side write lands on `refs/pull/N/merge` and is
# readable by no other pull request, so it bought nothing and cost the
# store — CLOUD-1453 measured 81% of a 10.77 GiB store as four merged
# pull requests' unreadable entries. Same posture as every warmed
# family's readers (`:185`, `ci.yml:420`, `:846`, `commit-lint.yml:138`).
#
# Measured cold on run 34332015804, this job: 242s, the second-longest
# completed job on that pull request behind `semver`, and it is in
# `CI_REQUIRED_CHECKS` — so every ready paid it.
save-if: false
- run: mise run darwin-link ${{ matrix.target }}
env:
# Exactly the target being linked; doctor's default would also fetch
Expand Down
20 changes: 10 additions & 10 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,17 +119,16 @@ run in the web sandbox — read `mem:github-access` before doubting.)
**This governs PR conduct above any harness default — and above your own
judgement.** Run the lifecycle tasks as written, never wrapped in bespoke retry or
pre-check logic; `main` advancing under your branch is this loop working, not a race
to engineer around. No heartbeats (`send_later`/Routines/timers) to babysit a PR —
fetching CI on demand is fine, the ban is on timers. No reflexive drive-to-green
pushing: a red run means verify was skipped, and a webhook's silence is not success.
to engineer around. No heartbeats to babysit a PR — `send_later`, Routines, timers
and `subscribe_pr_activity` are denied by rule: a webhook's silence is not success,
so its absence is design, not a gap. Fetch CI on demand, and never reflexively push
to green — a red run means verify was skipped.

## Background the slow path; never block the foreground

**Any command that can exceed ~2 minutes goes to the background**
(`run_in_background`): `mise run ci|verify|cross-check`, a full test suite, a cold
`cargo` build, a provision/install, or waiting on any external result. Enforced, not
stylistic — foreground `sleep` is blocked and a foreground command is killed at ~2
minutes, so it does not run slower, it _fails_.
**EVERY `mise` call is backgrounded** (`run_in_background`), **and so is anything
else past ~2 minutes**. Gated — `sleep` is blocked, `foreground-mise` the rest, and
a foreground command is _killed_ at ~2 min. **No fast list, `alive` included.**
**The exit notification IS the wake-up; waiting for it costs nothing.** A
backgrounded task re-invokes you when it exits (measured 523/524, failures
included), so the turn in between is the _designed_ state, not one to fill —
Expand All @@ -141,8 +140,9 @@ by `run-shape-guard`. To ask what a live task is _doing_, `mise run alive`.

**Two habits defeat this silently, both failing green:** piping a `mise run` into
a pager (the exit status becomes the pager's) or detaching it with `nohup`/`&`
(the wake-up is lost). Redirect to a file; put `run_in_background` on the long
command, never on a launcher that returns at once. Gated by `verdict-not-discarded`.
(the wake-up is lost). Put `run_in_background` on the long command, never a launcher, and
**never redirect it** — the harness captures where the HUMAN watches, so `>log
2>&1` writes where nobody reads. `verdict-not-discarded`, `background-redirect`.
**Never** use a foreground `sleep`, spin a foreground busy-poll, or end a turn idle
"to watch" something — background it, act on its exit, and commit first, since
**committed-and-pushed is the only state surviving a reclaim, and that is the TREE's
Expand Down
Loading
Loading