Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .claude/rules/policy-modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ than merely necessary: a preset ships everywhere, so its pattern could not name
consumer even if you wanted it to.

**The load-time tier cannot see this** — `policy test` reported 330 passed over
the dead version. `crates/batten/tests/policy_presets.rs` is what catches it,
the dead version. `crates/batten/tests/it/policy_presets.rs` is what catches it,
because it runs a preset's suite the way a consumer gets it. Give your own
compiled tier the same empty vocabulary (`patterns: &[]`) for the same reason: a
harness that declares the ids is supplying input no consumer supplies, and its
Expand Down
4 changes: 2 additions & 2 deletions .claude/rules/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ These load when you touch Rust; they do not need to be in context otherwise.
condition asserts its own premise before its conclusion; `tests/primitives.rs`'s
`every_permission_drop_asserts_its_own_premise` is the gate (CLOUD-249).
Prefer end-to-end tests over the
compiled binary (`crates/batten/tests/cli.rs`) for anything a consumer depends
compiled binary (`crates/batten/tests/it/cli.rs`) for anything a consumer depends
on — exit codes, output shape, flag handling.
- Branch on the named `ExitCode` variants in `crates/batten/src/exit.rs`, never
integer literals. One table, no per-verb exception: `2` is the policy verdict
Expand Down Expand Up @@ -153,7 +153,7 @@ arm has to reach 256 before it can see anything at all.
invocation series above and this one share a unit and nothing else, so a reader
plotting one stamp would put a 256-document sweep arm beside a `--help`
invocation and read the gap as a step change. `perf-record` takes the stamp from
`BENCH_METRIC`, and `crates/batten/tests/acquisition_metric.rs` asserts the task
`BENCH_METRIC`, and `crates/batten/tests/it/acquisition_metric.rs` asserts the task
sets it rather than trusting that it does.

**"Because nothing measured asks otherwise" is the literal wording, and it is the
Expand Down
2 changes: 1 addition & 1 deletion .claude/rules/scanning.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ that gate is not evidence you picked the right class; it only means you did not
substitute.

The mechanism over this file is correspondingly thin and is named for what it
does. `crates/batten/tests/scanner_taxonomy.rs` asserts that this file still
does. `crates/batten/tests/it/scanner_taxonomy.rs` asserts that this file still
names an instrument for each of the three question classes, still names the gate
over the substitution axis, still keeps row one free of a bare product name, and
still states the no-extension defect beside the recommendation — the same shape
Expand Down
6 changes: 3 additions & 3 deletions .claude/rules/toolchain.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ ledger recorded both identically. Write `kind:verb` or `kind:mechanism` as a fie
on the arm, beside the successor it qualifies:

```
// carried: mise-tasks/ready-lint.sh crates/batten/src/ready.rs kind:verb crates/batten/tests/ready.rs
// carried: mise-tasks/ready-lint.sh crates/batten/src/ready.rs kind:verb crates/batten/tests/it/ready.rs
```

A `policy/*.rego` or preset successor needs no field — its path already decides
Expand Down Expand Up @@ -348,7 +348,7 @@ mediating.
Serena tool to use instead travels as each row's `redirect`, so a move still
names `rename_memory` — the only route that rewrites `mem:` referrers. The
table in `batten.toml` is the one authority; the corpus that used to live in
`tests/memory-guard.bats` is `crates/batten/tests/mediated_verbs.rs`. There is
`tests/memory-guard.bats` is `crates/batten/tests/it/mediated_verbs.rs`. There is
no `BATTEN_MEMORY_GUARD_BYPASS`: a mediated deny takes the engine's own hatch,
`BATTEN_HOOK_BYPASS` — or the row's own `bypass_env` where it declares one
(CLOUD-437).
Expand Down Expand Up @@ -581,7 +581,7 @@ call` with no `CLOUD-*` key **in that same paragraph** stops the lap. Two open
is not nudged about one it already has. Silence is the default; a change-set is
reported once, because reporting overwrites the snapshot. Pointer-only — paths
and a count, never a byte of the file, asserted in
`crates/batten/tests/contract_drift.rs` — because a reminder carrying the new
`crates/batten/tests/it/contract_drift.rs` — because a reminder carrying the new
text is a mirror and a mirror is cleared by reading the hook instead of the
file. The shell task and `BATTEN_CONTRACT_DRIFT_BYPASS` are gone, and the
engine fails open on everything it cannot read. **The advisory has no hatch at
Expand Down
44 changes: 43 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,9 @@ strip = true
# THREE ARMS MEASURED on this container, 2026-08-30, each a cold
# `mise run test:cargo` over a cleared `target/debug`. The census counts
# `target/debug/deps`' extension-less linked binaries — the population
# `crates/batten/src/prune.rs:262-269` reads:
# `crates/batten/src/prune.rs`'s `superseded_in` reads through `artifact_key`
# (named rather than cited by line, because the line span this used to give had
# already drifted onto an unrelated field):
#
# arm artifacts bytes mean cold wall
# debug = 1 (the baseline) 125 15.53 GB 124.3 MB 231s
Expand Down Expand Up @@ -600,8 +602,48 @@ strip = true
# not re-proposed: rust-lld has been the default on this host triple since Rust
# 1.90, this repository pins 1.97.1, and `readelf -p .comment` over a built
# artifact reports `Linker: LLD 22.1.6`. The build already links with lld.
#
# SPLIT-DEBUGINFO MEASURED 2026-09-01 (CLOUD-1289) — the one arm CLOUD-1211
# deferred with its acceptance clause reading "Outstanding". Paired A/B on this
# container: three cold builds back to back in ONE process, so machine noise is
# common-mode and divides out, with two identical baselines bracketing the
# candidate rather than sitting on one side of it.
#
# arm cold wall artifacts linked bytes mean
# base-1 223.4s 147 10.19 GB 69.3 MB
# unpacked 208.9s 147 4.99 GB 34.0 MB
# base-2 213.7s 147 10.19 GB 69.3 MB
#
# THE TIME COLUMN IS NOT A FINDING, and is recorded only so nobody re-runs it.
# The two IDENTICAL baselines differ by 9.7s on their own — a null spread of
# 0.957 — and the candidate's ratio against the baseline mean is 0.956, which is
# inside it. That is the EXPECTED result rather than a disappointment: the prior
# art CLOUD-1211 cites (14s->4s, 8.7s->3.0s, rust-lang/cargo#9112) is macOS
# `dsymutil`, and `unpacked` is already cargo's default on macOS and not on
# Linux, so the mechanism that paid there is not the one in play on this triple.
#
# THE BYTE COLUMN IS THE FINDING, and its null has ZERO width — the two
# baselines are byte-identical at 10193048624, not merely close. 2.04x off the
# linked binaries, adopted on that alone, which is what CLOUD-1289's acceptance
# asks for: an arm that halves artifacts is worth adopting even where its time
# delta sits inside the null, because bytes are the binding constraint here
# (CLOUD-766).
#
# AND THE BYTES LEAVE THE DISK rather than moving to a sibling file, which is
# the question a SPLIT format has to be asked and which the linked census alone
# cannot answer: `target/debug/deps` 10.97 GB -> 5.87 GB and `target/debug`
# 13.03 GB -> 7.76 GB, because the 5.20 GB that left the binaries is replaced by
# 111.8 MB of `.dwo`. Those `.dwo` files are a class `prune.rs`'s closed
# `RECLAIMED_KINDS` cannot see, so they accumulate per build hash where the
# binary they came out of was reclaimable — CLOUD-1293, filed rather than fixed
# here because the fix is in `prune.rs` and the trade is 5.20 GB against 111.8 MB.
#
# `debug = 1` is untouched, so this changes WHERE debuginfo is stored and never
# whether it exists: every `batten` frame still reports its file and line, and
# the middle arm above stays rejected.
[profile.dev]
debug = 1
split-debuginfo = "unpacked"

# The dependency closure carries no debuginfo and IS optimised. Workspace code
# above keeps its line tables and stays unoptimised, so rebuilds of the code under
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ that **Batten never mints a `2` on it**: a `2` out of `exec` came from the wrapp
command, and nothing can mistake it for a verdict. Renumbering an output match to
`2` would spend that guarantee for a symmetry the table does not ask for. Decided
on CLOUD-292, with the three rejected alternatives recorded there; `crates/batten/src/exit.rs`
carries the reasoning and `crates/batten/tests/extension_surfaces.rs` gates it.
carries the reasoning and `crates/batten/tests/it/extension_surfaces.rs` gates it.

### Whatever you reach for: output is a pointer, never the payload

Expand All @@ -405,7 +405,7 @@ src/config.rs:41 no-hardcoded-token # the pointer
# never the token
```

`crates/batten/tests/pointer_only.rs` decides this rather than asserting it. It
`crates/batten/tests/it/pointer_only.rs` decides this rather than asserting it. It
seeds a corpus in which every byte a check can read is a unique canary, runs
**every leaf verb** of the command surface over it, and fails if a canary reaches
either channel. A verb added to the surface must declare which side of the law it
Expand All @@ -414,7 +414,7 @@ grows.

### Every example above is executed, not just written

`crates/batten/tests/extension_surfaces.rs` runs each command in this section
`crates/batten/tests/it/extension_surfaces.rs` runs each command in this section
against the compiled binary and asserts the exit code it claims. A drifted example
fails CI, so this documentation cannot rot into fiction.

Expand Down
72 changes: 63 additions & 9 deletions batten.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3296,7 +3296,7 @@ carried = "// carried:"
subsumed = "// subsumed:"
changed = "// changed:"
withdrawn = "// withdrawn:"
declared_in = "crates/batten/tests/*.rs"
declared_in = "crates/batten/tests/**/*.rs"

# The mirror direction: a disabled test is a deleted test that still counts, so
# the guard is on the token RISING.
Expand Down Expand Up @@ -3907,7 +3907,7 @@ no_fix_reason = "an IO crate reaching the evaluator is closed where it was enabl
[[rule]]
id = "no-key-leaves-the-schema-unannounced"
kind = "command"
glob = "crates/batten/tests/config_deprecations.rs"
glob = "crates/batten/tests/it/config_deprecations.rs"
check = "mise run test:config-deprecations"
severity = "deny"
scope = "tree"
Expand Down Expand Up @@ -4056,7 +4056,7 @@ base = "origin/main"
# withdrawal as one over a live subject and refuses it. A false refusal, in the
# direction that blocks correct work.
delta_sources = ["**"]
line_sources = ["mise-tasks/*.sh", "crates/batten/tests/*.rs"]
line_sources = ["mise-tasks/*.sh", "crates/batten/tests/**/*.rs"]
module = "policy/shell-retirement.rego"
severity = "deny"

Expand Down Expand Up @@ -4112,6 +4112,22 @@ delta_sources = ["**"]
module = "policy/filed-here.rego"
severity = "deny"

# CLOUD-1210's ratchet on the cargo test-target count.
#
# `delta_sources` is the whole tree rather than `crates/batten/tests/**`, because
# the module decides on the path's SHAPE and a narrower delta would hand it only
# paths it was going to accept anyway — a gate reading a pre-filtered input cannot
# tell "nothing was added" from "the filter removed it". The depth test lives in
# the module, where a reader can check it against Cargo's autodiscovery rule.
[[rule]]
id = "test-targets"
kind = "policy"
scope = "tree"
base = "origin/main"
delta_sources = ["**"]
module = "policy/test-targets.rego"
severity = "deny"

[[rule]]
id = "stop-posture"
kind = "policy"
Expand Down Expand Up @@ -5084,13 +5100,13 @@ keep = 2
mb = 7938
worst_mb = 7938
multiplier = 1
measured = "2026-08-31"
measured = "2026-09-01"

[prune.cold]
mb = 18984
worst_mb = 18984
multiplier = 1
measured = "2026-08-31"
measured = "2026-09-01"

# THE BASIS EACH FLOOR WAS MEASURED AGAINST (CLOUD-1158), because `measured` is a
# pointer to a basis and not the basis itself.
Expand Down Expand Up @@ -5142,14 +5158,35 @@ measured = "2026-08-31"
# The comparison runs in `batten target prune` (Surface::VerifyOnly), never at
# config load — `Prune::validate` is on the path every mediated tool call pays.

# THE 2026-09-01 MOVE, AND IT BREAKS THE MODEL'S PREMISE RATHER THAN JUST ITS
# NUMBER (CLOUD-1210). Every reading above treats a tracked test FILE as a proxy
# for a linked STEM, which was exact while cargo autodiscovered one target per
# top-level `crates/batten/tests/*.rs`. Grouping them ends that: 144 targets
# became 2, so the file count and the artifact count are no longer one series.
#
# Measured on this container, cold and clean, before and after the grouping under
# the same adopted `split-debuginfo` profile: linked artifacts 147 -> 4, linked
# bytes 4.99 GB -> 234 MB, `target/debug` 7.76 GB -> 2.05 GB. A `verify` lap that
# CLOUD-1210 recorded consuming 25403 MB now consumes 20-1272 MB.
#
# So `count` moves to the live 152 with `measured`, as this block instructs, and
# THE FLOORS DELIBERATELY DO NOT MOVE. Both are now far above what the tree needs,
# and that is the safe direction on its own terms — the block already records that
# a floor too LOW fails silently while one too high only refuses laps. Re-deriving
# them downward needs the independent measurement this block names (a build from
# an empty `target` for cold, a minimal post-prune tree for warm) and is
# CLOUD-1158's, which CLOUD-1210's own §2 names as out of scope while predicting
# exactly this basis move. Refreshing the count without claiming a floor
# measurement I did not take is the honest half of the remedy.

[prune.warm.basis]
glob = "crates/batten/tests/*.rs"
count = 140
glob = "crates/batten/tests/**/*.rs"
count = 152
tolerance = 10

[prune.cold.basis]
glob = "crates/batten/tests/*.rs"
count = 140
glob = "crates/batten/tests/**/*.rs"
count = 152
tolerance = 10

# THE REGROWABLE ROOTS THE ESCALATION MAY DROP (CLOUD-1157), in the order it drops
Expand Down Expand Up @@ -5951,6 +5988,23 @@ id = "R-OVERRIDE-PROSE-ONLY"
kind = "override"
precondition = "the prose IS the deliverable and cannot wait for the next change to these files"

[[verdict]]
id = "V-TEST-TARGET-ADDED"
gloss = "a new top-level crates/batten/tests/*.rs mints a second cargo test target"
class = """
Cargo autodiscovers one test target per top-level `crates/batten/tests/*.rs`, and \
rustc relinks the whole dependency closure into each one. Measured before \
CLOUD-1210 grouped them: 144 targets, 147 linked artifacts, and roughly 36s of \
the 48s a developer pays to rebuild after touching one `src/*.rs`. A file one \
segment deeper — inside the group directory carrying `main.rs` — is a module and \
mints no target, which is where a retirement's tier belongs.
"""

[[verdict.route]]
id = "R-ADD-IT-TO-THE-GROUP"
kind = "command"
target = "git mv the file under crates/batten/tests/it/ and declare it in that group's main.rs"

[[verdict]]
id = "V-FILED-UNREFINED"
gloss = "a row this branch created was never groomed to Ready, so filing cost nothing"
Expand Down
73 changes: 73 additions & 0 deletions crates/batten/examples/config-load-bench.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//! What `batten::config::load` costs over this repository's own committed
//! authority (CLOUD-1291).
//!
//! # The question, and the measurement that could not answer it
//!
//! `crates/batten/tests/common/mod.rs` re-reads and re-parses the committed
//! `batten.toml` on every fixture command it constructs — 761 static call sites
//! across the suite, none of them memoized. Whether that is worth fixing depends
//! on a number nobody had.
//!
//! The first attempt took it through a CLI verb, subtracting `batten --help` from
//! `batten config show` and calling the difference the parse. It is not: running
//! the same verb from a directory with no `batten.toml`, where nothing is parsed
//! at all, measured 30.2 ms against 29.1 ms in-repo — identical within noise. The
//! 22.5 ms was verb startup, paid whether or not a config exists. A 29 ms process
//! cannot resolve a cost that may be a millisecond, so the verb is the wrong
//! instrument and this target is the right one: one function call, timed in
//! process, with nothing else in the way.
//!
//! # Why an example target and not a verb
//!
//! `crates/batten/examples/acquisition-bench.rs`'s header owns this argument in
//! full and it applies unchanged: `crates/batten/tests/pointer_only.rs` sweeps
//! every leaf verb over a bare fixture corpus and refuses one that exits `3`, and
//! a benchmark has could-not-look as its only honest answer there. So the
//! measurement is a target the command surface does not carry — no verb, no
//! completion, no man page. It is still built by `--all-targets` and still held
//! to the same clippy bar.
//!
//! It also costs the integration-test census nothing: `examples/` is not
//! `tests/`, so this adds no linked test binary (CLOUD-1210).
//!
//! # Why the work is in `crates/batten/src/perf.rs`
//!
//! `Record`'s shape is a contract `perf-compare` parses and `perf-gate` greps,
//! and the percentile convention behind `p50` is what two readings must share
//! before their numbers can sit side by side. A bench with its own struct and its
//! own median is a second authority over both.
//!
//! # Reading the output
//!
//! One `arm=` record per arm in per-call milliseconds, the `parse/load` ratio —
//! whose distance from 1.0 is the READ's share — then the null spread the whole
//! thing must be read against. A saving inside that spread has measured no
//! effect, which for this row is a result and not a failure to deliver.
//!
//! Exit 0 measured / 1 could not look.

// The one sanctioned place to write to a stream: this target IS a binary
// boundary, exactly as `main.rs` is, and its whole output is the report.
#![allow(clippy::print_stdout, clippy::print_stderr)]

use std::path::Path;

fn main() -> std::process::ExitCode {
// The committed authority, relative to the repository root the task layer
// runs from — the same path `common::at_root("batten.toml")` resolves for the
// harness this is measuring on behalf of.
match batten::perf::config_load(Path::new("batten.toml")) {
Ok(reading) => {
print!("{reading}");
std::process::ExitCode::SUCCESS
}
// COULD NOT LOOK, in the `::error::` shape the workflow annotates, and
// never an empty reading that exits 0 — a bench reporting "measured, and
// there was nothing" over a run that never happened is the failure
// CLOUD-1208 hit twice in one session.
Err(reason) => {
eprintln!("::error:: {reason}");
std::process::ExitCode::FAILURE
}
}
}
Loading
Loading