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
215 changes: 0 additions & 215 deletions .claude/container-setup.sh

This file was deleted.

64 changes: 63 additions & 1 deletion batten.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2466,12 +2466,33 @@ no_fix_reason = "restore the tests, or waive the reduction deliberately; which o
# test or a `policy test` case, and both are reachable from there. A wave that
# needs a ledger somewhere else widens this glob deliberately rather than
# scattering arms — the walk is bounded by declaration on purpose.
#
# CLOUD-1080 adds the fourth arm, and the reason is a measured dead end rather
# than a wish. The three above all name a SUCCESSOR, because they were written for
# a suite migrating into the engine. A WITHDRAWAL has none: `.claude/container-
# setup.sh` was added and removed inside one session, and six of its eight cases
# described the wrapper's own existence — which script to prefer, what to fetch,
# what to verify about the fetched bytes — so nothing replaced them because
# nothing should have a subject to replace. The two that did have successors are
# `subsumed` and `changed` in that ledger.
#
# With three arms the only routes past that were a false `subsumed` — a ledger
# entry that lies in order to pass — or a `[[waiver]]`, which `config-lint`
# refuses as `waiver-added` unless the weakening was groomed onto the issue before
# the work started. Neither is honest, so the gate had no honest path, which makes
# it a defect rather than a verdict.
#
# It is admissible ONLY where the dying file's declared subject is absent at head,
# which is what keeps it strictly NARROWER than the waiver it replaces: a waiver
# admits every deletion under its path, and this admits one case at a time and
# only once the subject went with it. It owes a reason and names no target.
[rule.conserves]
case = "@test \""
close = "\""
carried = "// carried:"
subsumed = "// subsumed:"
changed = "// changed:"
withdrawn = "// withdrawn:"
declared_in = "crates/batten/tests/*.rs"

# The mirror direction: a disabled test is a deleted test that still counts, so
Expand Down Expand Up @@ -2978,7 +2999,16 @@ id = "shell-retirement"
kind = "policy"
scope = "tree"
base = "origin/main"
delta_sources = ["mise-tasks/**", "tests/**/*.bats"]
# THE SELECTOR IS `**` FOR THE FOURTH ARM (CLOUD-1080), and it is the same
# correction `prose-only` records one row down. What this row GOVERNS is unchanged
# — `governed_at_head` and `governed_when_deleted` still select `mise-tasks/**` and
# `tests/**/*.bats` and nothing else — but a withdrawal has to be able to see that
# its declared subject DIED, and a subject is routinely neither of those: the
# wrapper this arm was built for lived under `.claude/`. With the narrow list the
# subject never appears in `delta.deleted`, so the arm reads every honest
# 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"]
module = "policy/shell-retirement.rego"
severity = "deny"
Expand Down Expand Up @@ -3850,6 +3880,38 @@ id = "R-ADD-A-BINARY-TEST"
kind = "document"
target = ".claude/rules/policy-modules.md"

[[verdict]]
id = "V-WITHDRAWAL-SUBJECT-ALIVE"
gloss = "a `withdrawn` retirement arm was spent over a subject the tree still carries"
class = """
The condition that keeps the fourth arm narrower than a `[[waiver]]` over the \
path. A withdrawal claims that nothing replaced this file because the thing it \
governed should not exist — honest only where the subject went with it, and over \
a subject still standing it is a blanket permission to delete governed files. \
Either delete the declared subject in this same change, or name a successor on a \
`// carried:`, `// subsumed:` or `// changed:` row instead.
"""

[[verdict.route]]
id = "R-RETIRE-THE-SUBJECT-TOO"
kind = "document"
target = "batten.toml"

[[verdict]]
id = "V-WITHDRAWAL-UNEXPLAINED"
gloss = "a `withdrawn` retirement arm names neither a successor nor a reason"
class = """
The fourth arm names no successor by design, so the reason is the only thing a \
reader can check the claim against — and an arm carrying neither is a file \
deleted with a marker on it. Write the reason on the same row, after the retired \
path.
"""

[[verdict.route]]
id = "R-EXPLAIN-THE-WITHDRAWAL"
kind = "document"
target = "batten.toml"

[[verdict]]
id = "V-ANCESTRY-DECIDES-MERGEDNESS"
gloss = "a reachability answer decides merged-ness, which a rebased landing is invisible to"
Expand Down
Loading
Loading