Skip to content

feat(policy): the landing lease and the reland judgement, and the primitive the lease needed - #810

Merged
wenzowski merged 2 commits into
mainfrom
claude/landing-loop-bundle-4puk4i
Sep 1, 2026
Merged

wenzowski merged 2 commits into
mainfrom
claude/landing-loop-bundle-4puk4i

Conversation

@wenzowski

@wenzowski wenzowski commented Sep 1, 2026 •

Copy link
Copy Markdown
Contributor

Closes CLOUD-1280.

DO-NOT-CLOSE CLOUD-1269 — this PR serves it and does not complete it. Three of its
four predicates now exist (one here, one in #800, one dispositioned do-not-build
with a reason), but its "consumer #1 eats the same food" clause is still unmet:
lease-authorises-the-branch is inert in this repository until a [[recorder]]
row writes lease lines for it to read, and that wiring is a protected write needing
its own admission. It is the next commit, not a deferral. #800 already carries that
row into In Review.


CLOUD-1269 shipped one of its four landing predicates and CLOUD-1280 carried the
rest, recording that the other three name facts that cannot answer them. Two of
the three reasons that row first recorded were wrong
, and re-investigating them
is what this change is: it builds two more predicates onto the landing-loop
preset and settles the fourth in writing.

What each of the three became

predicate disposition
target-is-fast-forwardable renamed and built as already-landed-work-is-not-relanded. Neither named fact decides descendant-ness — git-refs deliberately dropped reachability (CLOUD-36 decides merged-ness by patch identity, now gated by policy/ancestry-decides-nothing.rego) and input.tree.landing answers has this work landed. The predicate is named for the fact that answers it.
lease-authorises-the-branch built, on a mechanism that needed one Rust primitive
spend-needs-a-verified-head not built, and the shape is decided rather than deferred. The recorded blocker — a policy row may not declare checks — was true and beside the point: required_checks_for widens across the whole rule table, so the policy row never needed to. The real blockers are rule 1 (a preset over input.facts.receipts.verify bakes a consumer's check name into every consumer's binary) and redundancy (it is what ready-needs-receipts already denies).

The lease, and why the clock stays outside

The boundary grades the lease with its own clock and reports the grade as an exit
status; the consumer's [[recorder]] maps that status to a word; the module
compares words. Rule::max_age is the landed precedent — the comparison happens
where the subject is already being read. So no clock reaches the engine, no
input.tree.instant is added and no policy schema regenerates
: CLOUD-1170's
refusal and CLOUD-1269's resolved-token decision both stand.

The fail-open asymmetry is conserved by the mechanism rather than by prose. An
exit status the consumer's table leaves unmapped records could-not-look, which
equals neither verdict token, so the refusal cannot hold. That matters because the
producer fails closed on an unreachable remote and the bash this replaces
deliberately does not: "a lease it cannot read stops EVERY job in the fleet, where
waving one matrix through costs one matrix."

Value::Branch is the one Rust primitive, and it is the admitted successor row
(CLOUD-369) that needs it. The producer's status arm grades the lease against the
clone; authorises grades it against the branch and admits one case status
cannot — a branch that reserved the slot behind the holder is buying the matrix
that overlaps the holder's merge, so refusing it cancels the very run the
reservation exists to start. write_records already resolved the branch to key the
record by and never handed it to an expression; this exposes what the writer holds.

The declared break

semver refused the first landing attempt and was right: Value::Branch is
enum_variant_added and Context.branch is constructible_struct_adds_field, so
an out-of-crate match over the enum and an out-of-crate construction of the struct
both stop compiling. CLOUD-1280's §6 said patch — a clause groomed before the
mechanism was chosen, and the mechanism it now specifies cannot be
patch-compatible. The subject is feat(recorder)! with a BREAKING CHANGE: footer,
and §6 is corrected on the row rather than left contradicting what landed.

Three defects found while getting the tiers green

Each is recorded where the next reader meets it, not only here:

  • A Rego set is unordered and de-duplicating, so "the last line" was not
    recoverable from the contains set the lease module first used. The record is a
    history; it is an array comprehension now.
  • regorus panics outright (node_idx out of bounds) on a defaulted helper rule
    here and on a some x in [rule] destructuring bind — a worse failure than the
    fault being guarded against, since it takes the whole bundle down at load.
  • A preset is several files in one package, so a test helper named recorded
    collided with graded-head-is-not-regraded.rego's and broke both suites —
    eleven failures, three in a module this change never touches, none of them
    reading as a collision.

Verification

  • mise run policy-test — 478 passed, 0 failed. This tier is insufficient by
    construction
    and is not the evidence: it reported 330 green over CLOUD-1161's
    two dead predicates.
  • mise run test:cargo -- --test it — 3609 passed, 0 failed, over the compiled
    binary with policy::Vocabulary::EMPTY, which is the tier that catches a preset
    shipping dead. Each predicate has its deny and its anti-vacuity mirror
    (CLOUD-418); the lease has the third outcome its asymmetry requires — an
    unreadable lease allows, distinguishable from both — plus both successor
    rows, since the admitting clause is otherwise satisfied by any reservation at all.
  • mise run semver — reproduced the original refusal, then green with the break
    declared.
  • mise run schema regenerated schema/batten.schema.json for the new Value
    variant. Never hand-edited.

Weakens

Weakens: rule-predicate-changed rule[landing-loop-preset].landing, groomed on
CLOUD-1280's Ready block. The reland predicate reads input.tree.landing, and the
only place a fact column can be declared is the [[rule]] row that enables the
preset — policy::load refuses two rows naming one source — so the existing row's
predicate necessarily moves. config-lint reports that as a change and
deliberately not as a ranking, so the clause declares the move rather than claiming
a lowering: without the column the predicate is undefined and the preset ships
dead, which is CLOUD-845's class.

No mise-tasks/*.sh and no tests/**/*.bats is opened, so V-SHELL-RULE-EDITED
and V-SHELL-RULE-ADDED are both untouched and bash-surface-not-growing is
unmoved.

@linear-code

linear-code Bot commented Sep 1, 2026 •

Copy link
Copy Markdown
CLOUD-1280 Three of CLOUD-1269's four landing predicates name facts that cannot answer them — and two of the three reasons this row first recorded were wrong

Why

CLOUD-1269's four-predicate table assigns each predicate the facts it reads. Three of those four assignments do not hold at head, and each was found while building the row rather than while reading it — so the row shipped one of four and this carries the rest.

That ratio is the finding, not an accident of this session: a refined row's fact column reads as checked and nothing checks it. Two of the three are refusals the engine states in its own docs (no_ancestry_decides_merged_ness, Fact::Instant's tree_key() = None), and the third is a column the config schema already refuses. All three were knowable before the row was marked Ready.

lease-authorises-the-branch — the freshness half is unresolvable on the tree surface

The row's fact column is "the lease record + a resolved freshness token". The record half is reachable: a [[recorder]] over a Bash call, Value::Section peeling branch: and next: out of captured stdout, pr-body-closes's shape (batten.toml:1615).

The freshness half has no mechanism. authorises (mise-tasks/land-lock.sh:1081) treats an expired lease as allow — [[ -z "$observed_sha" ]] || released || expired — so a module that cannot resolve expiry cannot tell expired from held by someone else and would deny where authorises allows. That is precisely the inversion the row names as its own failure mode: "a port that quietly makes it fail closed has laundered a stop-the-world into a gate."

Three routes, and each is closed:

  1. A clock on the tree surface. CLOUD-1170 decided against it and PR feat(facts)!: a supplied instant, four lease/liveness retirements, and two engine defects they exposed #793 built it that way deliberately: Fact::Instant takes Fact::Waived's shape, tree_key() is None, and it "reaches no module on any surface". Reversing that is that row's decision, not this one's.

  2. The boundary compares, via a recorder column. This row first said no program emits a freshness token. That was wrong — land-lock authorises already resolves freshness with its own clock and reports it as an exit code (0 run / 3 stop / 2 could-not-look, land-lock.sh:1051-1111), and Read::Status maps exit status to a token, so the shape looked exactly right. It fails for a different and harder reason: Program::args is a fixed Vec<String> frozen at config load (recorder.rs:371-373) with no template and no interpolation, while authorises takes its branch on ARGV and refuses exit 2 without it (land-lock.sh:138-147). run_program writes the evaluated expression to the child's STDIN only. A row could hard-code one branch forever or record unreadable on every call, and nothing in the expression language reaches $2. Worse, Value has no variant that yields the current branch at all (recorder.rs:231-325) — write_records knows it and uses it for the record key (lib.rs:6368) but never exposes it. So even a stdin-reading wrapper would need a Rust change, and the wrapper itself is a shell edit V-SHELL-RULE-EDITED refuses.

    A third obstacle sits behind those two: append_all APPENDS (recorder.rs:969) and recorder_records returns every line in write order, so the record is a HISTORY. A module reading it holds no clock — true — but also cannot tell today's run from an hour ago's, and record_path is branch-keyed with no per-lap partition.

  3. A compiled authority. recorder::Ask has one variant, Ready — the Definition-of-Ready grammar. Nothing else is askable.

A second session reached the same blocked destination by a different route, and that convergence is worth more than either finding alone. PR #793's refactor(ci)! commit tried to port the lease to a RECEIPT row rather than to a preset, and recorded on CLOUD-1275 that it is "blocked on a measured shape rather than on effort": branch_receipt_name really does spell the lease's own path byte-identically to what land-lock.sh's swap writes, but branch_validity answers StaleMain when a receipt carries no base line — and a lease receipt carries an expiry epoch and none, so such a row would refuse every ready, always.

So the receipt route fails in the SAME direction the preset route does: refuse-everything rather than the fail-open authorises conserves. Two independent mechanisms, one shape of failure, and neither is a matter of effort.

So this predicate needs a mechanism decision before it can be built at all, and the honest options are a Surface::Check freshness fact resolved at the boundary (CLOUD-1170's answer 3, still unbuilt) or a second recorder::Ask variant.

THE MECHANISM DECISION, IN WRITING (the first acceptance clause)

Decided: route 2, and it needs ONE Rust primitive rather than the three obstacles this row first recorded. The decision is written here before any module is written, which is what the acceptance asks for.

The freshness half is already resolved, by a verb this row did not examine. authorises is not the only arm that grades the lease: status (land-lock.sh:995-1048) applies released and expired with its own clock and reports the result as an exit code — 0 for unheld, released, expired or mine, 1 for held by another clone, 2 where observe could not read. So the freshness comparison happens where the lease is already being read, which is Rule::max_age's precedent exactly, and the module reads a token rather than an epoch. No clock on the tree surface, no input.tree.instant, no schema key — CLOUD-1170's refusal and CLOUD-1269's token decision are both conserved rather than reopened.

And it needs no argv, which is what closed route 2 before. status takes none, so Program::args being a frozen Vec<String> stops mattering: the row is args = ["status"] and the branch never has to reach $2.

**Fail-open is conserved by the **Read::Status MAPPING TABLE, not by luck. status fails CLOSED on an unreachable remote where authorises fails open — authorises's own header says so in as many words. An unmapped status is ABSENT and ABSENT is could-not-look, so a table declaring only 0 and 1 restores the asymmetry at the boundary: 2 maps to nothing, the column records could-not-look, and the module allows. That is the fail-open half obtained from the mechanism rather than asserted in prose.

What is still missing is exactly one primitive, and it is the successor row. status answers is the lease mine, per clone; authorises answers does the lease authorise this branch, and it admits one more case — the ADMITTED SUCCESSOR (CLOUD-369, land-lock.sh:1102). peek prints that field alone, so the record can carry it; the module then has to compare it against the CURRENT BRANCH, and no Value yields one (recorder.rs:231-325). Without it the port refuses a reserved successor that authorises allows — a fail-CLOSED deviation on one row, which is precisely the laundering CLOUD-1269 forbids, so shipping without the primitive is not an option.

**So the build is: a **Value variant yielding the current branch. write_records already computes it for the record key (lib.rs:6368) and never exposes it; this exposes what is in hand. Contained in recorder.rs, regenerates the config schema (§4 above), and is inside this row's own §1.

The stated bound, rather than a silence. recorder_records returns every line in write order, so the record is a HISTORY and the module reads the last line — an answer as fresh as the most recent call the recorder row selected, never now. That is a real bound and it is acceptable HERE because the selector is the landing call itself, so the line the lap reads is seconds old. A predicate wanting a stronger guarantee needs a per-lap partition, which is not this row's.

target-is-fast-forwardable — neither named fact decides descendant-ness

The row's fact column is input.tree.landing, input.tree["git-refs"]. Neither answers the predicate, and one of them says so in its own doc:

  • input.tree["git-refs"] deliberately dropped reachability. Fact::Landing's doc: "The fact GIT_REF deliberately does not carry. That row's own header says so: it dropped the reachability answer because no_ancestry_decides_merged_ness refused it, since CLOUD-36 decides merged-ness by PATCH IDENTITY and a rebased landing is invisible to ancestry." git::ref_facts (crates/batten/src/git.rs:3233) inserts (name, commit) and the schema pins additionalProperties: {"type": "string"}.
  • input.tree.landing answers a different question. It is whether this branch's work is on each declared target, by patch identity — {"verdict", "landed", "unlanded"}. "Has this work landed" is not "is this head a descendant".

The refusal of ancestry is deliberate and correct, so this is not a request to add it back — and it is now GATED rather than merely documented: no_ancestry_decides_merged_ness no longer exists as a test, having moved to policy/ancestry-decides-nothing.rego under CLOUD-756, which refuses merge-base, is-ancestor, --contains and --ancestry-path as arguments anywhere in src/. So no ahead/behind fact can be added without an argument at that gate.

What IS decidable from input.tree.landing, established from git.rs:2985-3110 and LandingFact at git.rs:3694-3705. verdict has exactly four values — landed, partially_landed, nothing_to_land, not_landed_within_window — and the schema declares only "string", so a module comparing against a token that does not exist passes validation and never holds.

The trap, and it is sharp: landed **is NOT **count(unlanded) == 0. A squash-landed branch reaches Verdict::Landed through cumulative_evidence, leaving per-commit evidence all None — so landed == true with a non-empty unlanded. And not_landed_within_window is an UNPROVEN absence, not "not landed": the module cannot see target_truncated or window, because Scan is not projected.

So the honest predicate available here is already-landed-work-is-not-relanded over input.tree.landing[target].landed — generic, since the target is the consumer's declared string, and reading the fact for what it says rather than for what the old name wanted.

spend-needs-a-verified-head — a policy row may not declare the receipts it reads

Found by the gate rather than by reading, which is the part worth keeping. The module was written, the preset wired, and the enabling row declared the roster exactly the way CLOUD-1269's §2 asks — the consumer's checks in batten.toml, out of the bundle. config-lint refused it at the pre-commit gate:

batten: rule landing-spend-preset: `checks` is not valid for kind "policy"

THAT DIAGNOSIS WAS WRONG, and the correct one kills the predicate rather than deferring it. checks is indeed not valid on a policy row (rules.rs:852-894), but the policy row never needed to declare it: required_checks_for (hook.rs:3159-3172) narrows by CALL via matching_receipt_rows and widens across the WHOLE rule table, and call_document serializes one document before the bundle loop (hook.rs:5484). So a policy module DOES read receipts a kind = "receipt" row declared — here ready-needs-receipts (batten.toml:502-521, pattern = "gh pr ready", checks = ["verify", "linear-check"]).

The real blockers are two, and neither is a missing column:

  1. Rule 1. A preset predicate over input.facts.receipts.verify bakes a CONSUMER's check name into every consumer's binary — the violation policy.rs:305-309 names for shipping this repository's job names inside ci-hygiene.
  2. Redundancy. The generic spelling — every receipt this call requires is valid — names nothing and is already what ready-needs-receipts denies. The preset would refuse what the receipt row refused, under a second set of words.

And the failure mode if shipped anyway is silent: delete or re-pattern that receipt row and facts.receipts projects null (Look::IsNot), the predicate is undefined, no violation is raised, and config-lint is clean because the policy row is independently valid. batten.toml:599-604 already documents exactly this coupling for agent-sourced.

Disposition: do not build. Not deferred pending a shape decision — the shape is decided and it is "not a preset".

What did ship

graded-head-is-not-regraded alone, as the landing-loop preset — tree-scoped, over input.tree.forge.

The surface split is still real and still forced: a [[rule]] carries one scope and policy::load refuses two rows naming one preset, source_key for a preset row being the preset's own name, so a bundle cannot span the tree and the mediated call. With only one predicate left buildable there is one preset.


Refinement — Ready (decide the mechanism each blocked predicate needs, then build it)

Refinement gate: Definition of Ready & Done. This body carries only specializations.

  • Authority boundary (§1). crates/batten/src/facts.rs or crates/batten/src/recorder.rs for whichever mechanism is taken; new crates/batten/src/policy/presets/landing-loop/*.rego; crates/batten/src/verdict.rs; crates/batten/tests/; and the enabling rows in batten.toml. No mise-tasks/*.sh and no tests/**/*.bats — which is the constraint that closed route 2 above, so a plan reaching for one has not found a blocked row, it has written §1 in the wrong shape.
  • Computable predicate (§2). For the lease: a lease record whose branch does not match, with freshness resolved as live, is refused; the same record resolved as expired is not; an unreadable lease is not. The middle case is the one no current mechanism can produce, and it is the whole row. For the second: whichever predicate is decided on, its deny and its mirror.
  • Deliberately not in scope (§2). Adding ancestry to input.tree["git-refs"] — no_ancestry_decides_merged_ness refused it and CLOUD-36's patch-identity verdict stands. Adding a raw instant key — CLOUD-1170 decided that and feat(facts)!: a supplied instant, four lease/liveness retirements, and two engine defects they exposed #793 built the decision. Retiring any landing program — CLOUD-1148's.
  • Effect (§3). read.
  • Generated artifacts (§4). A new fact regenerates schema/policy-input.schema.json; a new recorder::Ask variant regenerates the config schema. mise run fix; never hand-edit.
  • **Weakens: **rule-predicate-changed at rule[landing-loop-preset].landing. The second predicate reads input.tree.landing, and the only place a fact column can be declared is the [[rule]] row that enables the preset — policy::load refuses two rows naming one source (policy.rs:813), so a separate row is not available and the existing row's predicate necessarily moves. config-lint reports this as a CHANGE and deliberately not as a ranking (trust.rs:527-533: "whether one glob is narrower than another is a judgement this module refuses to make, but that the predicate moved at all is a byte comparison"), so this clause declares the move rather than claiming a lowering: the column ADDS a fact a dead predicate had nothing to read, and without it the preset ships dead — CLOUD-845's class, and what CLOUD-1161's ci-hygiene shipped twice.
  • Output and exit (§5). Pointer-only: the lease key, the ref, the commit. Never a lease body.
  • Commit / bump (§6). feat(policy) — patch.
  • Test obligation (§7). Over the compiled binary, with policy::Vocabulary::EMPTY. Shown able to fail per CLOUD-418: each predicate's deny and its anti-vacuity mirror, plus the lease's third case — an unreadable lease allows, distinguishable from both a live lease and a refusing one. The fail-open asymmetry is the load-bearing half and a suite that cannot show all three has not tested it.
  • Blockers (§8). relatedTo CLOUD-1269 (the row that shipped the other two), CLOUD-1170 (whose answer 3 is one of the two candidate mechanisms and is unbuilt), CLOUD-1148 (the migration these are the successors for), CLOUD-499 (the lease's conserved verdict).

Acceptance

  • The mechanism for lease freshness is decided in writing — a boundary-resolved fact, a second recorder::Ask, or a recorded refusal that this predicate stays bash — before any module is written.
  • If it is built, an expired lease naming another branch allows, and that case is exercised over the compiled binary rather than with with input as.
  • The second predicate is either renamed to the question input.tree.landing actually answers, or dropped with a reason.
  • The receipts predicate has a shape decided — a policy row that may declare checks, or an explicit statement that it reads another row's declaration and what that couples it to.
  • CLOUD-1269's four-predicate table is corrected so the next reader does not re-derive both findings.

CLOUD-1269 Ship the `landing-loop` preset — CLOUD-1170 names PRESET as the lease predicate's home and no row owns building one, so the generic half of 3,538 lines of landing bash has a disposition and no destination

Why

CLOUD-1170 took the answer and named the home in as many words:

*"A lease predicate over *(record, instant) is generic — every consumer with a landing lease has that shape — so it is a PRESET, with the TTL and the lease's identity as consumer config."

Nothing owns building it. CLOUD-1170 owns the facts (the supplied instant, the liveness record) and its §2 excludes retiring any member. CLOUD-1148 owns the migration and, until an owner correction on 2026-08-31, excluded "shipping a landing preset" outright. So the disposition was recorded twice and the destination zero times — the punt shape AGENTS.md names: an unbuilt mechanism awaited instead of the instance in hand.

This row is the destination.

What is generic, and why that is the test that matters

Landing judgements split three ways, and only one third belongs in a preset:

part example home
effect and loop fetch, rebase, push, the CAS on the lease ref, the poll outside the engine, unchanged — CLOUD-1170's own split
consumer fact which branch is trunk, the required-check roster, the TTL, the lease's identity batten.toml
generic predicate given this lease record and this instant, may this branch spend a matrix? this preset

.claude/rules/policy-modules.md's "module or preset" test is the authority: a preset only when the predicate stays generic once the consumer's facts are pulled into batten.toml. Each predicate below passes it — none names a branch, a check roster, a task or a tracker key, which is also non-negotiable rule 1 reaching the vendored tier via presets_are_inside_the_rule_one_glob.

The four predicates

THIS TABLE'S FACT COLUMN WAS WRONG FOR THREE OF THE FOUR ROWS, AND THE DISPOSITION COLUMN IS THE CORRECTION (CLOUD-1280). Each of the three was found while BUILDING the row rather than while reading it, which is the finding: a refined row's fact column reads as checked and nothing checks it.

predicate the practice facts disposition
lease-authorises-the-branch exactly one branch at a time spends a matrix; a lapsed lease authorises nobody the lease record + a resolved freshness token blocked on a mechanism, CLOUD-1280. The record half is reachable; the FRESHNESS half has no producer the engine can read. All three routes are closed at head — a tree-surface clock is CLOUD-1170's refusal, a [[recorder]] over authorises cannot reach $2 (Program::args is a fixed Vec<String> and no Value yields the current branch) and the record is an append-only history with no per-lap partition, and recorder::Ask has one variant
target-is-fast-forwardable a landing attempt on a head that is not a descendant is refused locally, before the matrix ~~input.tree.landing~~~~, ~~~~input.tree["git-refs"]~~ RENAMED and shipped as already-landed-work-is-not-relanded. Neither named fact decides descendant-ness: git-refs deliberately dropped reachability (CLOUD-36 decides merged-ness by patch identity, now gated by policy/ancestry-decides-nothing.rego), and input.tree.landing answers has this work landed, which is a different question. The predicate is named for the fact that answers it
graded-head-is-not-regraded a SHA the forge already graded is not re-run, and a red one is not readied input.tree.forge shipped, PR #800
spend-needs-a-verified-head the event that starts CI is refused unless this exact head carries a live verification receipt receipt validity, per Rule::max_age DO NOT BUILD, and the shape is decided rather than deferred. A policy row may not declare checks — but it never needed to, since required_checks_for widens across the whole rule table. The real blockers are non-negotiable rule 1 (a preset over input.facts.receipts.verify bakes a consumer's check name into every consumer's binary) and redundancy (the generic spelling is what ready-needs-receipts already denies)

lease-authorises-the-branch is mise-tasks/land-lock.sh:1051's authorises arm, which is already a pure function and says so: "Read-only and side-effect free… a pure function of (lease state, branch) so the suite can drive every row without a second clone."

Its fail-open asymmetry is conserved verbatim, and that is the load-bearing half. land-lock.sh:1069 — "FAIL OPEN, EVERYWHERE IT CANNOT TELL. Every other refusal in this file fails closed, and this one deliberately does not: a lease it cannot read stops EVERY job in the fleet, where waving one matrix through costs one matrix." A port that quietly makes it fail closed has laundered a stop-the-world into a gate.

The instant reaches the predicate as a RESOLVED TOKEN, not as arithmetic

Owner decision, 2026-08-31, and it is a refinement of CLOUD-1170's "one value per invocation, on the input, treated as data" rather than a contradiction of it: the engine is still handed the instant and still never reads a clock. What changes is what Rego sees.

The precedent is landed. crates/batten/src/rules.rs:1351-1377 (Rule::max_age):

*"THE CLOCK IS THE BOUNDARY'S, NEVER adjudicate's. The comparison happens where the receipt is already being read… That is the waiver table's precedent: a waiver lapses on a date, and *today() *is handed in rather than taken inside, pinned by adjudicate_reads_no_clock_even_now_that_a_waiver_can_lapse. This column buys a fourth *Validity and no clock in the core."

So the boundary compares and the module reads fresh / expired / could-not-look. Three consequences, each a reason:

  1. **No 25th **input.tree key and no schema regeneration. The 24 keys stand.
  2. Byte-stable output survives by construction. An integer instant on the input makes two evaluations over one tree differ whenever the module does arithmetic on it; a resolved token does not. That is CLOUD-1170's own third acceptance clause — "the same evaluation repeated produces identical bytes" — obtained rather than asserted.
  3. No second authority over time. max_age already compares; a raw instant would let every module compare too, differently.

A raw input.tree.instant is not in this row's scope and nothing in the loop needs one. If a second predicate ever wants arithmetic over an arbitrary timestamp, that is its own row.

The two ways a preset ships DEAD, both already measured here

Not cautionary: both have happened in this repository.

  1. Every pattern literal is written INLINE. A [[pattern]] row is consumer config, so data.batten.patterns["x"] resolves to undefined for a consumer who wrote none; Rego reads undefined as does not hold; the module loads clean and decides nothing. crates/batten/src/policy.rs states it at the exemption's own site — the demand is *"unsatisfiable… a consumer cannot add a *[[pattern]] row on its behalf, and the preset cannot read one." CLOUD-934 predicted it in those words; CLOUD-1161's ci-hygiene preset is it happening, two predicates dead.
  2. The compiled tier supplies the empty vocabulary (patterns: &[]). batten policy test reported 330 passed over the dead version, because the load-time tier cannot see this class. crates/batten/tests/policy_presets.rs, running the bundle the way a consumer gets it, is the only tier that catches it.

And per CLOUD-857: anchor on input.call.segments, never split(input.call.command, " "), for anything that turns out to be mediated-call scoped.


Refinement — Ready (ship the generic landing judgements as a vendored, overridable bundle)

Refinement gate: Definition of Ready & Done. This body carries only specializations.

  • Authority boundary (§1). New crates/batten/src/policy/presets/landing-loop/*.rego; the PRESETS entry in crates/batten/src/policy.rs; the VendoredVerdict rows in crates/batten/src/verdict.rs's vendored-presets section; arms in crates/batten/tests/policy_presets.rs; and the enabling [[rule]] rows in this repository's own batten.toml. Purely additive — no mise-tasks/*.sh and no tests/**/*.bats is opened, so V-SHELL-RULE-EDITED and V-SHELL-RULE-ADDED are both untouched, and no program retires in this row.
  • Computable predicate (§2). A consumer enabling preset = "landing-loop" and supplying a lapsed lease record is refused, naming the lease key; the same consumer with a live lease is not. Each of the four predicates carries that pair.
  • Consumer ci: check in the main-branch protection ruleset #1 eats the same food (§2). This repository enables the bundle in the same change, the way batten.toml's trunk-based-preset row already does — "the only way the surface gets exercised by something other than its own tests." The row states a position on overlap with the enabled ci-hygiene bundle, which judges workflow wiring, so the two do not report one practice twice.
  • Overridability is per verdict (§2). Each predicate raises its own token in VENDORED, with a route; lease-authorises-the-branch and graded-head-is-not-regraded carry a route with a precondition (a wedged holder starving the fleet; a re-grade genuinely wanted after a runner fault). target-is-fast-forwardable carries none — rebasing is the route. Contrast V-SHELL-RULE-EDITED, whose single routeless verdict is the design and not an oversight.
  • Deliberately not in scope (§2). Retiring land.sh, land-lock.sh or main-watch.sh — CLOUD-1148 owns the migration and its ci-lease-precondition fetch-and-exec precondition is untouched here. Adding a raw instant key. Changing what landing currently decides: the port is behaviour-conserving, and CLOUD-499's liveness-not-progress verdict is carried, not revisited.
  • Effect (§3). read. A preset is include_str! at build time — no network, no registry, no trust-on-first-use — and every predicate reads facts the boundary already resolved. evaluator-io-check stays the gate.
  • Generated artifacts (§4). The published preset-name enum regenerates from preset_names(). mise run fix; never hand-edit. No schema/policy-input.schema.json change, which is the point of the token decision above.
  • Output and exit (§5). Pointer-only: the lease key, the ref, the SHA, the check name — never a lease body, never a fetched payload, never a process listing. The 0/1/2/3 table is untouched; a lease that cannot be read is could-not-look and allows, per the fail-open asymmetry above.
  • Commit / bump (§6). feat(policy) — patch.
  • Test obligation (§7). Over the compiled binary, in crates/batten/tests/policy_presets.rs, **with **patterns: &[] — the load-time tier is insufficient by construction and 330 green tests over two dead predicates is the measurement. Shown able to fail per CLOUD-418: for each predicate, the deny case and its anti-vacuity mirror, without which the first is satisfied by a gate that refuses everything. Plus the third case this row's own asymmetry needs: an unreadable lease allows, distinguishable from both.
  • Blockers (§8). blockedBy CLOUD-1170 — the supplied instant and the liveness record are its deliverables, and three of the four predicates are inert without a fact layer to read. relatedTo CLOUD-1148 (the migration parent, whose §2 exclusion of this row was struck on 2026-08-31), CLOUD-1181 (a preset is three parallel hardcoded tables, which this row adds a sixth row to and does not fix), CLOUD-836 (the vendored-preset mechanism), CLOUD-934 (the inline-regex exemption), CLOUD-1161 (the two dead predicates), CLOUD-857 (the segments anchor), CLOUD-418, CLOUD-499.

Acceptance

  • preset_names() includes landing-loop, and enabling it by name in a [[rule]] row loads.
  • Each of the four predicates has a deny case, an anti-vacuity mirror, and — for the lease — an unreadable-lease case that allows, all in crates/batten/tests/policy_presets.rs over the compiled binary with patterns: &[].
  • No data.batten.patterns[...] reference appears anywhere under presets/landing-loop/.
  • Every verdict raised is declared in VENDORED, and every VENDORED row added is raised by a predicate — both directions, which the loader already refuses.
  • This repository enables the bundle, and the enabling row states its position on ci-hygiene overlap.
  • No mise-tasks/ program and no .bats suite is added, edited or deleted, and bash-surface-not-growing is unmoved.
  • CLOUD-1148's child rows can cite this bundle as the successor for the generic half of authorises, rather than re-deriving it.

Filed 2026-08-31 after an owner decision that the landing loop ships as an overridable preset. The disposition existed on CLOUD-1170 and the exclusion on CLOUD-1148; neither was a destination.

Review in Linear

@coderabbitai

coderabbitai Bot commented Sep 1, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 20 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Free

Run ID: e519e7b3-5a15-4699-b091-050baecf27c7

📥 Commits

Reviewing files that changed from the base of the PR and between 0b31cae and cb33679.

📒 Files selected for processing (9)
  • batten.toml
  • crates/batten/src/lib.rs
  • crates/batten/src/policy.rs
  • crates/batten/src/policy/presets/landing-loop/already-landed-work-is-not-relanded.rego
  • crates/batten/src/policy/presets/landing-loop/lease-authorises-the-branch.rego
  • crates/batten/src/recorder.rs
  • crates/batten/src/verdict.rs
  • crates/batten/tests/it/policy_presets.rs
  • schema/batten.schema.json

Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Essentials by visiting https://app.coderabbit.ai/settings/billing.

Comment @coderabbitai help to get the list of available commands.

…nswers it

CLOUD-1269 asked for `target-is-fast-forwardable` over `input.tree.landing` and
`input.tree["git-refs"]`. Neither fact decides descendant-ness, and neither can
be made to: CLOUD-36 decides merged-ness by PATCH IDENTITY because a rebased
landing is invisible to ancestry, `git-refs` dropped its reachability answer for
that reason, and `policy/ancestry-decides-nothing.rego` now refuses `merge-base`,
`is-ancestor`, `--contains` and `--ancestry-path` as arguments anywhere in
`src/`. So the fact was never going to arrive.

What `input.tree.landing` DOES answer is whether the target already carries this
branch's work, which is a real landing judgement — so the predicate ships under
that name rather than under one its fact cannot support. Renaming quietly would
have been the worse move; CLOUD-1280 carries the correction.

TWO TRAPS IN ONE FACT, AND THIS COMMIT FELL INTO THE SECOND BEFORE ITS OWN SUITE
CAUGHT IT.

`landed` is not `count(unlanded) == 0`: a squash-landed branch reaches its
verdict through the cumulative diff, so every per-commit proof is absent and
`unlanded` is non-empty while `landed` is true. A module reading the array calls
a squash-landed branch outstanding — the false negative patch identity exists to
prevent. That one was caught by reading.

`landed` is not `verdict == "landed"` either, and that one was not. The boolean
is also true for `nothing_to_land`, which is what a checkout sitting on the trunk
with no distinct work answers — so refusing on it refuses a STATE rather than an
ATTEMPT, and the state is normal. Measured: four `cli::` fixtures built from the
committed config reported `origin/main already-landed-work-is-not-relanded`
before the narrowing. Both traps are now in the module header with that
measurement, and `nothing_to_land` has a clean case in both tiers.

`not_landed_within_window` is deliberately not refused. The scan is windowed and
`target_truncated` is not projected, so a module cannot tell a proven absence
from "I stopped looking" — refusing it would be a verdict about how far the
engine looked wearing the clothes of a verdict about the branch.

`landing = ["origin/main"]` on the enabling row is what makes the fact exist at
all: the engine resolves landing only for DECLARED targets, so the bundle without
it would load clean, pass both tiers, and decide nothing. That is CLOUD-845's
class and what CLOUD-1161's `ci-hygiene` shipped twice. The target is consumer
config precisely because it names this repository's trunk; the preset names none.

Refs: CLOUD-1280

Admits: 8dcfee86e3267762a0716a9cfbc1fba755289534cd5c298c11265497f3f2e93d
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: 4d5bd0c
Admits-epoch: 650a76ba70a8b5645ffc58aedb1bdde72394e39026b5c1391a926934ea49702c
Admits-author: alec@wenzowski.com
Admits-prev: 8427b359e00e0b95d087bb6d24490e253e6a31de4334706e1e94f81973449d32
Admits-answer-lost: Without the column `input.tree.landing` projects `null`, the predicate is undefined, and the preset ships DEAD — loading clean, passing its own tests and the preset suite, and enforcing nothing. That is CLOUD-845's class and exactly what CLOUD-1161's `ci-hygiene` shipped twice; a gate that decides nothing is worse than an absent one because it reads as coverage.
Admits-answer-precondition: `batten.toml` IS the owning surface for a `[[rule]]` row: it is the one authority the engine reads for rules, so a fact column cannot be declared anywhere else. This adds `landing = ["origin/main"]` to the existing `landing-loop-preset` row so the second predicate has a fact to read, and it lands in a PR diff a reviewer sees.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is circular for this subject, because `batten.toml` IS the owning surface for a rule's fact column — no other file the engine consults declares one. R-RESTORE-IT would revert the column and reinstate the dead gate.
Weakens: rule-predicate-changed rule[landing-loop-preset].landing
CLOUD-1269's first landing predicate, built on the mechanism CLOUD-1280
decided: the boundary grades the lease with its own clock and reports the
grade as an exit status, the consumer's `[[recorder]]` maps that status to a
word, and the module compares words. `Rule::max_age` is the landed precedent
— the comparison happens where the subject is already being read — so no
clock reaches the engine, no `input.tree.instant` is added and no schema
regenerates. CLOUD-1170's refusal stands.

THE FAIL-OPEN ASYMMETRY IS CONSERVED BY THE MECHANISM RATHER THAN BY PROSE.
An exit status the consumer's table leaves unmapped records could-not-look,
which equals neither verdict token, so the refusal cannot hold. That matters
because the producer fails CLOSED on an unreachable remote and the bash this
replaces deliberately does not: "a lease it cannot read stops EVERY job in
the fleet, where waving one matrix through costs one matrix." A port that
quietly fails closed has laundered a stop-the-world into a gate.

`Value::Branch` is the one Rust primitive, and it is the ADMITTED SUCCESSOR
row that needs it (CLOUD-369). The producer's `status` arm grades the lease
against the CLONE; `authorises` grades it against the BRANCH and admits one
case `status` cannot — a branch that reserved the slot behind the holder is
buying the matrix that overlaps the holder's merge, so refusing it cancels
the very run the reservation exists to start. `write_records` already
resolved the branch to key the record by and never handed it to an
expression; this exposes what the writer holds. Could-not-look is `None`, so
a detached HEAD compares against nothing rather than against a placeholder.

The predicate names no branch, no remote, no program and no record. A
record's name is the consumer's, so it selects on a generic `lease` kind
column instead — rule 1 reaching the vendored tier.

Three defects found while getting the two tiers green, each recorded where
the next reader meets it:

  * A Rego set is unordered and de-duplicating, so "the last line" was not
    recoverable from the `contains` set this module first used. The record is
    a history and the reading is the last line, so it is an array
    comprehension now.
  * regorus panics outright (`node_idx out of bounds`) on a defaulted helper
    rule here, and on a `some x in [rule]` destructuring bind — a worse
    failure than the fault being guarded against, since it takes the whole
    bundle down at load. Both spellings are gone and the guard is inline.
  * A preset is several FILES in ONE package, so a test helper named
    `recorded` collided with `graded-head-is-not-regraded.rego`'s and broke
    BOTH suites — eleven failures, three of them in a module this change
    never touches, and none of them reading as a collision.

The pointer is the REFUSED branch and not the holder's: the producer reports
the holder only in the prose line a human reads, and parsing that would turn
a message into an interface.

Test obligation: nine cases over the compiled binary with
`policy::Vocabulary::EMPTY`, the tier that catches a preset shipping dead.
The asymmetry needs three outcomes rather than two — refuse, authorise, and a
could-not-look distinguishable from both — plus both successor rows, since
the admitting clause is otherwise satisfied by any reservation at all.

BREAKING CHANGE: `recorder::Value` gains a `Branch` variant and
`recorder::Context` gains a `branch` field, so an out-of-crate match over the
enum and an out-of-crate construction of the struct both stop compiling.
`semver` named both (`enum_variant_added`, `constructible_struct_adds_field`)
and it is right: this is the API moving, not an accident of the diff.

CLOUD-1280's §6 said `patch`, and that clause was groomed BEFORE the mechanism
was chosen. The mechanism it now names is a `Value` variant, which cannot be
patch-compatible — the row's own §4 anticipated exactly this shape when it said
a new variant regenerates the config schema. Marking the break is the honest
reading; keeping the subject patch-compatible would have meant either a wrong
declaration or a worse mechanism chosen to dodge the gate.

Refs: CLOUD-1280
Refs: CLOUD-1269
@wenzowski
wenzowski marked this pull request as ready for review September 1, 2026 13:12
@wenzowski
wenzowski force-pushed the claude/landing-loop-bundle-4puk4i branch from 0f5a76b to cb33679 Compare September 1, 2026 13:12
@sonarqubecloud

sonarqubecloud Bot commented Sep 1, 2026

Copy link
Copy Markdown

❌ The last analysis has failed.

See analysis details on SonarQube Cloud

@wenzowski

Copy link
Copy Markdown
Contributor Author

/fast-forward

@wenzowski
wenzowski merged commit cb33679 into main Sep 1, 2026
10 of 11 checks passed
@wenzowski
wenzowski deleted the claude/landing-loop-bundle-4puk4i branch September 1, 2026 13:44
wenzowski added a commit that referenced this pull request Sep 1, 2026
CLOUD-1280 landed `lease-authorises-the-branch` and this repository declared no
`[[recorder]]` writing a lease line, so `input.tree.records` carried none and
the predicate allowed unconditionally. Fail-open rather than a dead gate — the
refusal it could not reach is the refusal it is designed not to reach — but
every reading of it was a test fixture, which is the one thing CLOUD-1269 calls
"the only way the surface gets exercised by something other than its own tests."

Three non-obvious choices, each PROBED rather than assumed:

  * `status`, not `authorises`. The `authorises` arm answers the module's exact
    question and takes the branch on ARGV; `Program::args` is a fixed
    `Vec<String>` frozen at config load, so a row could only hard-code one
    branch forever. `status` takes none.
  * `peek next`, not `peek`. `peek` with no field argument is exit 2 with 51
    bytes of USAGE TEXT on stdout, and `render_column` folds whitespace — so the
    record's shape survives and the successor column silently carries prose that
    can never equal a branch. That is a fail-CLOSED deviation on the one row
    `Value::Branch` exists to keep open, and it was live in the first draft.
  * `2` is deliberately unmapped in the `status` table. `status` fails closed
    where it cannot observe the lease; `authorises` fails open. An unmapped
    status records could-not-look, which equals neither token, so the refusal
    cannot hold. The OMISSION is what restores the asymmetry at the boundary —
    adding a `"2"` row inverts the one behaviour the port exists to conserve.

THE ORDERING BOUND, STATED WHERE THE ROW LIVES. A recorder writes on the
post-tool event, and `mise run land` runs its whole lap inside ONE Bash call, so
nothing is written while a lap runs and the line `batten check` reads is
whatever the call before `land` left. `linear-check` is the step the contract
puts immediately before `land`, which makes the reading seconds old rather than
a lap old. On lap 2 and after nothing refreshes it, so a lease a rival acquired
during lap 1 is not seen — under-denying, which is the sanctioned direction for
a predicate whose whole asymmetry is that a reading it could not take allows.

The wide selector was priced and rejected: every Bash call would keep the record
always-fresh and put a remote lease observation on the mediated path of every
call, which `perf-assert` budgets against. `satisfied` is evaluated before any
column, so a narrow selector spawns nothing on an ordinary call — asserted, not
assumed, by the selector's own anti-vacuity case.

Test obligation: seven cases over the compiled binary in
`crates/batten/tests/it/lease_record.rs`, driving `batten hook` and reading the
file back. The preset suite structurally cannot be this tier — a `with input as`
case fabricates the very line the engine may be unable to write. The
could-not-look case asserts the recorded TOKEN rather than the file's existence,
because a case reading only the file would pass over a table that mapped `2`.

Weakens: recorder-added recorder[landing-lease]

Refs: CLOUD-1298
Refs: CLOUD-1269

Admits: 8b8119b1795d43416aa547233174231a5a75e42828d43440f3df535ee5befaf3
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: cb33679
Admits-epoch: 8ae3d03b504fed658464f45a75ce2f4963f458a806777852c084456400109939
Admits-author: alec@wenzowski.com
Admits-prev: 8dcfee86e3267762a0716a9cfbc1fba755289534cd5c298c11265497f3f2e93d
Admits-answer-lost: Without the recorder the preset predicate merged in #810 has no record to read, so `input.tree.records` carries no lease line and the predicate allows unconditionally. That is the fail-open direction and so not a dead gate in CLOUD-845's sense, but it means consumer #1 does not eat its own food — the clause CLOUD-1269 names as "the only way the surface gets exercised by something other than its own tests" — and a landing lap keeps spending CI against a lease nothing in the engine reads.
Admits-answer-precondition: `batten.toml` IS the owning surface for a `[[recorder]]`, a `[program]` and a `[[pattern]]` row: it is the one authority the engine reads for all three, so a recorder that writes the landing-lease record cannot be declared anywhere else. This adds the row that makes `lease-authorises-the-branch` non-decorative in this repository, and it lands in a PR diff a reviewer sees.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is circular for this subject, because `batten.toml` IS the owning surface for a recorder, a program and a pattern row — no other file the engine consults declares one. R-RESTORE-IT would revert the rows and leave the predicate reading a record nothing writes.

Admits: c90a5c16aadfea21155819bed70c8150b24134cc025a3b2728a7b836ef5e9e83
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: cb33679
Admits-epoch: d900ba911dec5d109316dc19515aded5283414e1bf481ca30fa363aec876a210
Admits-author: alec@wenzowski.com
Admits-prev: 8b8119b1795d43416aa547233174231a5a75e42828d43440f3df535ee5befaf3
Admits-answer-lost: Without the recorder the preset predicate merged in #810 has no record to read, so `input.tree.records` carries no lease line and the predicate allows unconditionally. Fail-open, so not a dead gate in CLOUD-845's sense, but consumer #1 then does not eat its own food — the clause CLOUD-1269 calls "the only way the surface gets exercised by something other than its own tests" — and a landing lap keeps spending CI against a lease nothing in the engine reads.
Admits-answer-precondition: `batten.toml` IS the owning surface for a `[[recorder]]` and a `[[pattern]]` row: it is the one authority the engine reads for both, so the recorder that writes the landing-lease record and the selector it narrows on cannot be declared anywhere else. They are one block in one edit because an admission is single-use and the two rows are one mechanism. It lands in a PR diff a reviewer sees.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is circular for this subject, because `batten.toml` IS the owning surface for a recorder and a pattern row — no other file the engine consults declares either. R-RESTORE-IT would revert the block and leave the predicate reading a record nothing writes.

Admits: d7b0aaf76565dfa1a3ca87a2a2454c0e210bd854260e69f2bcebcd506ad4b28b
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: cb33679
Admits-epoch: 8a8bfc7d345f36b6d4d97458d63cf6aecb8216a100325631b4243c7a240efca3
Admits-author: alec@wenzowski.com
Admits-prev: c90a5c16aadfea21155819bed70c8150b24134cc025a3b2728a7b836ef5e9e83
Admits-answer-lost: Without the fix the successor column records a usage-error string on every write. `render_column` folds whitespace so the record SHAPE survives, which is what makes this silent: the module compares that string against the branch, finds them unequal, and the refusal stands. That is a fail-CLOSED deviation on the admitted-successor row — precisely the laundering CLOUD-1269 forbids and the exact case `Value::Branch` was added to prevent.
Admits-answer-precondition: `batten.toml` IS the owning surface for a `[program]` row, so the argv a recorder column runs cannot be corrected anywhere else. This fixes a defect in the block admitted moments ago: `land-lock peek` REQUIRES a field argument and the row omitted it, so the program exited 2 and wrote a usage line to stdout that the column would have recorded as the successor. Probed directly — `peek` alone is exit 2 with 51 bytes of usage text, `peek next` is exit 0 and empty. It lands in a PR diff a reviewer sees.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is circular for this subject, because `batten.toml` IS the owning surface for a `[program]` row's argv — no other file the engine consults declares one. R-RESTORE-IT would restore the argv-less invocation and reinstate the fail-closed successor row.
wenzowski added a commit that referenced this pull request Sep 1, 2026
`filed-over-own-diff` refuses `batten.toml` on this branch, and the route its
own class declares — R-CLOSE-IT-IN-THE-BODY — is the one taken: PR #812's body
opens with `Closes CLOUD-1298`. The gate cannot see it, and the reason is a
mechanism gap rather than an unmet condition.

The exemption reads the `pr-closes` RECORD, minted by a `[[recorder]]` over a
`gh pr view` Bash call. This environment has no `gh`, so the evidence channel is
unavailable — and fabricating a tool result to mint the record would forge the
very evidence the exemption exists to demand.

TWO FURTHER FACTS, FOUND WHILE ESTABLISHING THAT, AND THE FIRST IS A DEFECT:

  * The record was STALE, still naming CLOUD-1269 and CLOUD-1279 from the PR
    this branch carried before it was reset onto the merged trunk.
    `record_path` is branch-keyed with no PR identity, so a reused branch name
    inherits the previous PR's closes-record and the exemption then reads the
    wrong PR's keys. Same family as the lease record's history bound one level
    up: no per-PR partition.
  * Removing that stale line does not exempt either. The predicate needs a
    POSITIVE record naming the key, so an absent channel refuses where an
    absent finding would have passed.

Admits: e8a1d7bfdb26149ed897edccf84b90248b37b2f15ac077991be687da6d75f0f8
Admits-rule: filed-here
Admits-verdict: V-FILED-OVER-OWN-DIFF
Admits-subject: batten.toml
Admits-head: 717afda
Admits-epoch: c4d86ca484c6cc808f9252e1394b9ad10993d6646fdcf5864522e2af3d23a020
Admits-author: alec@wenzowski.com
Admits-prev: -
Admits-answer-lost: Nothing is deferred, so the toll prices a punt that did not happen. Paying it any other way means either not filing the row — leaving the wiring's ordering bound, its rejected wide-selector alternative and its `peek next` defect recorded nowhere — or splitting the file from the fix across two branches, which is the batching this repository's whole trunk discipline exists to prevent.
Admits-answer-precondition: CLOUD-1298 DOCUMENTS this change rather than deferring it. Its §1 names `batten.toml` because `batten.toml` is what the change edits — the two `[program]` rows, the `[[pattern]]` and the `[[recorder]]` that make #810's landed predicate read something real. The row was filed and fixed in the same branch, and the fix is in this diff.
Admits-answer-rejected-route: R-CLOSE-IT-IN-THE-BODY IS THE ROUTE I TOOK, and the override is only because the gate cannot see it. PR #812's body opens with `Closes CLOUD-1298`. The exemption reads the `pr-closes` RECORD, which is minted by a `[[recorder]]` over a `gh pr view` Bash call, and this environment has no `gh` CLI — so the evidence channel is unavailable rather than unsatisfied, and I will not fabricate a tool result to mint it. Two further facts found while establishing that: the record was also STALE, still naming CLOUD-1269/CLOUD-1279 from the PR this branch carried before it was reset, because `record_path` is branch-keyed with no PR identity; and removing that stale line does not exempt either, since the predicate needs a positive record rather than an absent one. R-FIX-IT-HERE does not apply because there is nothing to fix — the row is not a punt. R-FILE-IT-AFTER-LANDING would land the mechanism with its own reasoning unrecorded, which is the failure the row exists to prevent.
Weakens: program-changed program[land-lock-status]
Weakens: program-changed program[land-lock-peek]
Weakens: recorder-added recorder[landing-lease]
wenzowski added a commit that referenced this pull request Sep 1, 2026
…e alone

A branch NAME outlives the branch it described. `git checkout -B <name>
origin/main` discards the commits that were the branch while every name-keyed
file survives — CLOUD-516's finding, which the claim receipt already answers
for itself by recording the base it was made against. A `[[recorder]]`'s
record had no such discriminator at all, so the next attempt on a reused
branch name read the previous one's lines as its own.

MEASURED HERE, NOT REASONED ABOUT. After PR #810 merged and this branch was
reset onto the new trunk, `pr-closes.<branch>` still held `closes
2:CLOUD-1269,CLOUD-1279` — that PR's keys. The PR actually open was #812,
closing CLOUD-1298, which appeared nowhere in the record.

THE DANGEROUS DIRECTION IS THE SILENT ONE. `filed-over-own-diff` exempts a row
the PR CLOSES and reads that from this record, so a stale record does not
merely refuse an honest file-then-fix: a row named by the PREVIOUS PR's
closes-record would be EXEMPTED on a PR that does not close it, with nothing
downstream to re-check.

THE CLAIM RATHER THAN THE BASE, and the difference is what makes it usable. A
base moves on every rebase and `land` rebases every lap, so keying a record on
one would discard it mid-landing — the failure this prevents, arriving by
another route. A claim is re-minted per PULL and is stable across every rebase
in between, so it partitions exactly the attempts that must not see each other.

`claimed_token` is order-insensitive over a multi-key claim, or a re-claim of
the same work would partition itself away from its own record. `None` is
could-not-look and keeps the OLD path, which is what makes this a partition
rather than a migration: nothing that could not be attributed is moved, and an
unclaimed branch behaves exactly as before.

THREE READERS, AND THE THIRD IS THE ONE A NARROW FIX MISSES. `append_all`
writes, `recorder_records` projects the tree fact — and `filed-here`'s own
end-of-turn checklist reads the board record directly in `lib.rs`. Without the
same partition there it would list a previous attempt's rows as this one's.

Test obligation: four cases over the compiled binary, driving `batten hook`
twice under two claims on one branch name. The false-exemption case is the one
a naive suite misses, so it is written first and asserts the ABSENCE of the
previous attempt's key; its anti-vacuity mirror proves one claim still
accumulates across calls, without which the case is satisfied by a partition
so eager that no record survives a lap at all.

Refs: CLOUD-1300
Refs: CLOUD-516
wenzowski added a commit that referenced this pull request Sep 1, 2026
CLOUD-1280 landed `lease-authorises-the-branch` and this repository declared no
`[[recorder]]` writing a lease line, so `input.tree.records` carried none and
the predicate allowed unconditionally. Fail-open rather than a dead gate — the
refusal it could not reach is the refusal it is designed not to reach — but
every reading of it was a test fixture, which is the one thing CLOUD-1269 calls
"the only way the surface gets exercised by something other than its own tests."

Three non-obvious choices, each PROBED rather than assumed:

  * `status`, not `authorises`. The `authorises` arm answers the module's exact
    question and takes the branch on ARGV; `Program::args` is a fixed
    `Vec<String>` frozen at config load, so a row could only hard-code one
    branch forever. `status` takes none.
  * `peek next`, not `peek`. `peek` with no field argument is exit 2 with 51
    bytes of USAGE TEXT on stdout, and `render_column` folds whitespace — so the
    record's shape survives and the successor column silently carries prose that
    can never equal a branch. That is a fail-CLOSED deviation on the one row
    `Value::Branch` exists to keep open, and it was live in the first draft.
  * `2` is deliberately unmapped in the `status` table. `status` fails closed
    where it cannot observe the lease; `authorises` fails open. An unmapped
    status records could-not-look, which equals neither token, so the refusal
    cannot hold. The OMISSION is what restores the asymmetry at the boundary —
    adding a `"2"` row inverts the one behaviour the port exists to conserve.

THE ORDERING BOUND, STATED WHERE THE ROW LIVES. A recorder writes on the
post-tool event, and `mise run land` runs its whole lap inside ONE Bash call, so
nothing is written while a lap runs and the line `batten check` reads is
whatever the call before `land` left. `linear-check` is the step the contract
puts immediately before `land`, which makes the reading seconds old rather than
a lap old. On lap 2 and after nothing refreshes it, so a lease a rival acquired
during lap 1 is not seen — under-denying, which is the sanctioned direction for
a predicate whose whole asymmetry is that a reading it could not take allows.

The wide selector was priced and rejected: every Bash call would keep the record
always-fresh and put a remote lease observation on the mediated path of every
call, which `perf-assert` budgets against. `satisfied` is evaluated before any
column, so a narrow selector spawns nothing on an ordinary call — asserted, not
assumed, by the selector's own anti-vacuity case.

Test obligation: seven cases over the compiled binary in
`crates/batten/tests/it/lease_record.rs`, driving `batten hook` and reading the
file back. The preset suite structurally cannot be this tier — a `with input as`
case fabricates the very line the engine may be unable to write. The
could-not-look case asserts the recorded TOKEN rather than the file's existence,
because a case reading only the file would pass over a table that mapped `2`.

Weakens: recorder-added recorder[landing-lease]

Refs: CLOUD-1298
Refs: CLOUD-1269

Admits: 8b8119b1795d43416aa547233174231a5a75e42828d43440f3df535ee5befaf3
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: cb33679
Admits-epoch: 8ae3d03b504fed658464f45a75ce2f4963f458a806777852c084456400109939
Admits-author: alec@wenzowski.com
Admits-prev: 8dcfee86e3267762a0716a9cfbc1fba755289534cd5c298c11265497f3f2e93d
Admits-answer-lost: Without the recorder the preset predicate merged in #810 has no record to read, so `input.tree.records` carries no lease line and the predicate allows unconditionally. That is the fail-open direction and so not a dead gate in CLOUD-845's sense, but it means consumer #1 does not eat its own food — the clause CLOUD-1269 names as "the only way the surface gets exercised by something other than its own tests" — and a landing lap keeps spending CI against a lease nothing in the engine reads.
Admits-answer-precondition: `batten.toml` IS the owning surface for a `[[recorder]]`, a `[program]` and a `[[pattern]]` row: it is the one authority the engine reads for all three, so a recorder that writes the landing-lease record cannot be declared anywhere else. This adds the row that makes `lease-authorises-the-branch` non-decorative in this repository, and it lands in a PR diff a reviewer sees.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is circular for this subject, because `batten.toml` IS the owning surface for a recorder, a program and a pattern row — no other file the engine consults declares one. R-RESTORE-IT would revert the rows and leave the predicate reading a record nothing writes.

Admits: c90a5c16aadfea21155819bed70c8150b24134cc025a3b2728a7b836ef5e9e83
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: cb33679
Admits-epoch: d900ba911dec5d109316dc19515aded5283414e1bf481ca30fa363aec876a210
Admits-author: alec@wenzowski.com
Admits-prev: 8b8119b1795d43416aa547233174231a5a75e42828d43440f3df535ee5befaf3
Admits-answer-lost: Without the recorder the preset predicate merged in #810 has no record to read, so `input.tree.records` carries no lease line and the predicate allows unconditionally. Fail-open, so not a dead gate in CLOUD-845's sense, but consumer #1 then does not eat its own food — the clause CLOUD-1269 calls "the only way the surface gets exercised by something other than its own tests" — and a landing lap keeps spending CI against a lease nothing in the engine reads.
Admits-answer-precondition: `batten.toml` IS the owning surface for a `[[recorder]]` and a `[[pattern]]` row: it is the one authority the engine reads for both, so the recorder that writes the landing-lease record and the selector it narrows on cannot be declared anywhere else. They are one block in one edit because an admission is single-use and the two rows are one mechanism. It lands in a PR diff a reviewer sees.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is circular for this subject, because `batten.toml` IS the owning surface for a recorder and a pattern row — no other file the engine consults declares either. R-RESTORE-IT would revert the block and leave the predicate reading a record nothing writes.

Admits: d7b0aaf76565dfa1a3ca87a2a2454c0e210bd854260e69f2bcebcd506ad4b28b
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: cb33679
Admits-epoch: 8a8bfc7d345f36b6d4d97458d63cf6aecb8216a100325631b4243c7a240efca3
Admits-author: alec@wenzowski.com
Admits-prev: c90a5c16aadfea21155819bed70c8150b24134cc025a3b2728a7b836ef5e9e83
Admits-answer-lost: Without the fix the successor column records a usage-error string on every write. `render_column` folds whitespace so the record SHAPE survives, which is what makes this silent: the module compares that string against the branch, finds them unequal, and the refusal stands. That is a fail-CLOSED deviation on the admitted-successor row — precisely the laundering CLOUD-1269 forbids and the exact case `Value::Branch` was added to prevent.
Admits-answer-precondition: `batten.toml` IS the owning surface for a `[program]` row, so the argv a recorder column runs cannot be corrected anywhere else. This fixes a defect in the block admitted moments ago: `land-lock peek` REQUIRES a field argument and the row omitted it, so the program exited 2 and wrote a usage line to stdout that the column would have recorded as the successor. Probed directly — `peek` alone is exit 2 with 51 bytes of usage text, `peek next` is exit 0 and empty. It lands in a PR diff a reviewer sees.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is circular for this subject, because `batten.toml` IS the owning surface for a `[program]` row's argv — no other file the engine consults declares one. R-RESTORE-IT would restore the argv-less invocation and reinstate the fail-closed successor row.
wenzowski added a commit that referenced this pull request Sep 1, 2026
`filed-over-own-diff` refuses `batten.toml` on this branch, and the route its
own class declares — R-CLOSE-IT-IN-THE-BODY — is the one taken: PR #812's body
opens with `Closes CLOUD-1298`. The gate cannot see it, and the reason is a
mechanism gap rather than an unmet condition.

The exemption reads the `pr-closes` RECORD, minted by a `[[recorder]]` over a
`gh pr view` Bash call. This environment has no `gh`, so the evidence channel is
unavailable — and fabricating a tool result to mint the record would forge the
very evidence the exemption exists to demand.

TWO FURTHER FACTS, FOUND WHILE ESTABLISHING THAT, AND THE FIRST IS A DEFECT:

  * The record was STALE, still naming CLOUD-1269 and CLOUD-1279 from the PR
    this branch carried before it was reset onto the merged trunk.
    `record_path` is branch-keyed with no PR identity, so a reused branch name
    inherits the previous PR's closes-record and the exemption then reads the
    wrong PR's keys. Same family as the lease record's history bound one level
    up: no per-PR partition.
  * Removing that stale line does not exempt either. The predicate needs a
    POSITIVE record naming the key, so an absent channel refuses where an
    absent finding would have passed.

Admits: e8a1d7bfdb26149ed897edccf84b90248b37b2f15ac077991be687da6d75f0f8
Admits-rule: filed-here
Admits-verdict: V-FILED-OVER-OWN-DIFF
Admits-subject: batten.toml
Admits-head: 717afda
Admits-epoch: c4d86ca484c6cc808f9252e1394b9ad10993d6646fdcf5864522e2af3d23a020
Admits-author: alec@wenzowski.com
Admits-prev: -
Admits-answer-lost: Nothing is deferred, so the toll prices a punt that did not happen. Paying it any other way means either not filing the row — leaving the wiring's ordering bound, its rejected wide-selector alternative and its `peek next` defect recorded nowhere — or splitting the file from the fix across two branches, which is the batching this repository's whole trunk discipline exists to prevent.
Admits-answer-precondition: CLOUD-1298 DOCUMENTS this change rather than deferring it. Its §1 names `batten.toml` because `batten.toml` is what the change edits — the two `[program]` rows, the `[[pattern]]` and the `[[recorder]]` that make #810's landed predicate read something real. The row was filed and fixed in the same branch, and the fix is in this diff.
Admits-answer-rejected-route: R-CLOSE-IT-IN-THE-BODY IS THE ROUTE I TOOK, and the override is only because the gate cannot see it. PR #812's body opens with `Closes CLOUD-1298`. The exemption reads the `pr-closes` RECORD, which is minted by a `[[recorder]]` over a `gh pr view` Bash call, and this environment has no `gh` CLI — so the evidence channel is unavailable rather than unsatisfied, and I will not fabricate a tool result to mint it. Two further facts found while establishing that: the record was also STALE, still naming CLOUD-1269/CLOUD-1279 from the PR this branch carried before it was reset, because `record_path` is branch-keyed with no PR identity; and removing that stale line does not exempt either, since the predicate needs a positive record rather than an absent one. R-FIX-IT-HERE does not apply because there is nothing to fix — the row is not a punt. R-FILE-IT-AFTER-LANDING would land the mechanism with its own reasoning unrecorded, which is the failure the row exists to prevent.
Weakens: program-changed program[land-lock-status]
Weakens: program-changed program[land-lock-peek]
Weakens: recorder-added recorder[landing-lease]
wenzowski added a commit that referenced this pull request Sep 1, 2026
…e alone

A branch NAME outlives the branch it described. `git checkout -B <name>
origin/main` discards the commits that were the branch while every name-keyed
file survives — CLOUD-516's finding, which the claim receipt already answers
for itself by recording the base it was made against. A `[[recorder]]`'s
record had no such discriminator at all, so the next attempt on a reused
branch name read the previous one's lines as its own.

MEASURED HERE, NOT REASONED ABOUT. After PR #810 merged and this branch was
reset onto the new trunk, `pr-closes.<branch>` still held `closes
2:CLOUD-1269,CLOUD-1279` — that PR's keys. The PR actually open was #812,
closing CLOUD-1298, which appeared nowhere in the record.

THE DANGEROUS DIRECTION IS THE SILENT ONE. `filed-over-own-diff` exempts a row
the PR CLOSES and reads that from this record, so a stale record does not
merely refuse an honest file-then-fix: a row named by the PREVIOUS PR's
closes-record would be EXEMPTED on a PR that does not close it, with nothing
downstream to re-check.

THE CLAIM RATHER THAN THE BASE, and the difference is what makes it usable. A
base moves on every rebase and `land` rebases every lap, so keying a record on
one would discard it mid-landing — the failure this prevents, arriving by
another route. A claim is re-minted per PULL and is stable across every rebase
in between, so it partitions exactly the attempts that must not see each other.

`claimed_token` is order-insensitive over a multi-key claim, or a re-claim of
the same work would partition itself away from its own record. `None` is
could-not-look and keeps the OLD path, which is what makes this a partition
rather than a migration: nothing that could not be attributed is moved, and an
unclaimed branch behaves exactly as before.

THREE READERS, AND THE THIRD IS THE ONE A NARROW FIX MISSES. `append_all`
writes, `recorder_records` projects the tree fact — and `filed-here`'s own
end-of-turn checklist reads the board record directly in `lib.rs`. Without the
same partition there it would list a previous attempt's rows as this one's.

Test obligation: four cases over the compiled binary, driving `batten hook`
twice under two claims on one branch name. The false-exemption case is the one
a naive suite misses, so it is written first and asserts the ABSENCE of the
previous attempt's key; its anti-vacuity mirror proves one claim still
accumulates across calls, without which the case is satisfied by a partition
so eager that no record survives a lap at all.

Refs: CLOUD-1300
Refs: CLOUD-516
wenzowski added a commit that referenced this pull request Sep 2, 2026
CLOUD-1280 landed `lease-authorises-the-branch` and this repository declared no
`[[recorder]]` writing a lease line, so `input.tree.records` carried none and
the predicate allowed unconditionally. Fail-open rather than a dead gate — the
refusal it could not reach is the refusal it is designed not to reach — but
every reading of it was a test fixture, which is the one thing CLOUD-1269 calls
"the only way the surface gets exercised by something other than its own tests."

Three non-obvious choices, each PROBED rather than assumed:

  * `status`, not `authorises`. The `authorises` arm answers the module's exact
    question and takes the branch on ARGV; `Program::args` is a fixed
    `Vec<String>` frozen at config load, so a row could only hard-code one
    branch forever. `status` takes none.
  * `peek next`, not `peek`. `peek` with no field argument is exit 2 with 51
    bytes of USAGE TEXT on stdout, and `render_column` folds whitespace — so the
    record's shape survives and the successor column silently carries prose that
    can never equal a branch. That is a fail-CLOSED deviation on the one row
    `Value::Branch` exists to keep open, and it was live in the first draft.
  * `2` is deliberately unmapped in the `status` table. `status` fails closed
    where it cannot observe the lease; `authorises` fails open. An unmapped
    status records could-not-look, which equals neither token, so the refusal
    cannot hold. The OMISSION is what restores the asymmetry at the boundary —
    adding a `"2"` row inverts the one behaviour the port exists to conserve.

THE ORDERING BOUND, STATED WHERE THE ROW LIVES. A recorder writes on the
post-tool event, and `mise run land` runs its whole lap inside ONE Bash call, so
nothing is written while a lap runs and the line `batten check` reads is
whatever the call before `land` left. `linear-check` is the step the contract
puts immediately before `land`, which makes the reading seconds old rather than
a lap old. On lap 2 and after nothing refreshes it, so a lease a rival acquired
during lap 1 is not seen — under-denying, which is the sanctioned direction for
a predicate whose whole asymmetry is that a reading it could not take allows.

The wide selector was priced and rejected: every Bash call would keep the record
always-fresh and put a remote lease observation on the mediated path of every
call, which `perf-assert` budgets against. `satisfied` is evaluated before any
column, so a narrow selector spawns nothing on an ordinary call — asserted, not
assumed, by the selector's own anti-vacuity case.

Test obligation: seven cases over the compiled binary in
`crates/batten/tests/it/lease_record.rs`, driving `batten hook` and reading the
file back. The preset suite structurally cannot be this tier — a `with input as`
case fabricates the very line the engine may be unable to write. The
could-not-look case asserts the recorded TOKEN rather than the file's existence,
because a case reading only the file would pass over a table that mapped `2`.

Weakens: recorder-added recorder[landing-lease]

Refs: CLOUD-1298
Refs: CLOUD-1269

Admits: 8b8119b1795d43416aa547233174231a5a75e42828d43440f3df535ee5befaf3
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: cb33679
Admits-epoch: 8ae3d03b504fed658464f45a75ce2f4963f458a806777852c084456400109939
Admits-author: alec@wenzowski.com
Admits-prev: 8dcfee86e3267762a0716a9cfbc1fba755289534cd5c298c11265497f3f2e93d
Admits-answer-lost: Without the recorder the preset predicate merged in #810 has no record to read, so `input.tree.records` carries no lease line and the predicate allows unconditionally. That is the fail-open direction and so not a dead gate in CLOUD-845's sense, but it means consumer #1 does not eat its own food — the clause CLOUD-1269 names as "the only way the surface gets exercised by something other than its own tests" — and a landing lap keeps spending CI against a lease nothing in the engine reads.
Admits-answer-precondition: `batten.toml` IS the owning surface for a `[[recorder]]`, a `[program]` and a `[[pattern]]` row: it is the one authority the engine reads for all three, so a recorder that writes the landing-lease record cannot be declared anywhere else. This adds the row that makes `lease-authorises-the-branch` non-decorative in this repository, and it lands in a PR diff a reviewer sees.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is circular for this subject, because `batten.toml` IS the owning surface for a recorder, a program and a pattern row — no other file the engine consults declares one. R-RESTORE-IT would revert the rows and leave the predicate reading a record nothing writes.

Admits: c90a5c16aadfea21155819bed70c8150b24134cc025a3b2728a7b836ef5e9e83
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: cb33679
Admits-epoch: d900ba911dec5d109316dc19515aded5283414e1bf481ca30fa363aec876a210
Admits-author: alec@wenzowski.com
Admits-prev: 8b8119b1795d43416aa547233174231a5a75e42828d43440f3df535ee5befaf3
Admits-answer-lost: Without the recorder the preset predicate merged in #810 has no record to read, so `input.tree.records` carries no lease line and the predicate allows unconditionally. Fail-open, so not a dead gate in CLOUD-845's sense, but consumer #1 then does not eat its own food — the clause CLOUD-1269 calls "the only way the surface gets exercised by something other than its own tests" — and a landing lap keeps spending CI against a lease nothing in the engine reads.
Admits-answer-precondition: `batten.toml` IS the owning surface for a `[[recorder]]` and a `[[pattern]]` row: it is the one authority the engine reads for both, so the recorder that writes the landing-lease record and the selector it narrows on cannot be declared anywhere else. They are one block in one edit because an admission is single-use and the two rows are one mechanism. It lands in a PR diff a reviewer sees.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is circular for this subject, because `batten.toml` IS the owning surface for a recorder and a pattern row — no other file the engine consults declares either. R-RESTORE-IT would revert the block and leave the predicate reading a record nothing writes.

Admits: d7b0aaf76565dfa1a3ca87a2a2454c0e210bd854260e69f2bcebcd506ad4b28b
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: cb33679
Admits-epoch: 8a8bfc7d345f36b6d4d97458d63cf6aecb8216a100325631b4243c7a240efca3
Admits-author: alec@wenzowski.com
Admits-prev: c90a5c16aadfea21155819bed70c8150b24134cc025a3b2728a7b836ef5e9e83
Admits-answer-lost: Without the fix the successor column records a usage-error string on every write. `render_column` folds whitespace so the record SHAPE survives, which is what makes this silent: the module compares that string against the branch, finds them unequal, and the refusal stands. That is a fail-CLOSED deviation on the admitted-successor row — precisely the laundering CLOUD-1269 forbids and the exact case `Value::Branch` was added to prevent.
Admits-answer-precondition: `batten.toml` IS the owning surface for a `[program]` row, so the argv a recorder column runs cannot be corrected anywhere else. This fixes a defect in the block admitted moments ago: `land-lock peek` REQUIRES a field argument and the row omitted it, so the program exited 2 and wrote a usage line to stdout that the column would have recorded as the successor. Probed directly — `peek` alone is exit 2 with 51 bytes of usage text, `peek next` is exit 0 and empty. It lands in a PR diff a reviewer sees.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is circular for this subject, because `batten.toml` IS the owning surface for a `[program]` row's argv — no other file the engine consults declares one. R-RESTORE-IT would restore the argv-less invocation and reinstate the fail-closed successor row.
wenzowski added a commit that referenced this pull request Sep 2, 2026
`filed-over-own-diff` refuses `batten.toml` on this branch, and the route its
own class declares — R-CLOSE-IT-IN-THE-BODY — is the one taken: PR #812's body
opens with `Closes CLOUD-1298`. The gate cannot see it, and the reason is a
mechanism gap rather than an unmet condition.

The exemption reads the `pr-closes` RECORD, minted by a `[[recorder]]` over a
`gh pr view` Bash call. This environment has no `gh`, so the evidence channel is
unavailable — and fabricating a tool result to mint the record would forge the
very evidence the exemption exists to demand.

TWO FURTHER FACTS, FOUND WHILE ESTABLISHING THAT, AND THE FIRST IS A DEFECT:

  * The record was STALE, still naming CLOUD-1269 and CLOUD-1279 from the PR
    this branch carried before it was reset onto the merged trunk.
    `record_path` is branch-keyed with no PR identity, so a reused branch name
    inherits the previous PR's closes-record and the exemption then reads the
    wrong PR's keys. Same family as the lease record's history bound one level
    up: no per-PR partition.
  * Removing that stale line does not exempt either. The predicate needs a
    POSITIVE record naming the key, so an absent channel refuses where an
    absent finding would have passed.

Admits: e8a1d7bfdb26149ed897edccf84b90248b37b2f15ac077991be687da6d75f0f8
Admits-rule: filed-here
Admits-verdict: V-FILED-OVER-OWN-DIFF
Admits-subject: batten.toml
Admits-head: 717afda
Admits-epoch: c4d86ca484c6cc808f9252e1394b9ad10993d6646fdcf5864522e2af3d23a020
Admits-author: alec@wenzowski.com
Admits-prev: -
Admits-answer-lost: Nothing is deferred, so the toll prices a punt that did not happen. Paying it any other way means either not filing the row — leaving the wiring's ordering bound, its rejected wide-selector alternative and its `peek next` defect recorded nowhere — or splitting the file from the fix across two branches, which is the batching this repository's whole trunk discipline exists to prevent.
Admits-answer-precondition: CLOUD-1298 DOCUMENTS this change rather than deferring it. Its §1 names `batten.toml` because `batten.toml` is what the change edits — the two `[program]` rows, the `[[pattern]]` and the `[[recorder]]` that make #810's landed predicate read something real. The row was filed and fixed in the same branch, and the fix is in this diff.
Admits-answer-rejected-route: R-CLOSE-IT-IN-THE-BODY IS THE ROUTE I TOOK, and the override is only because the gate cannot see it. PR #812's body opens with `Closes CLOUD-1298`. The exemption reads the `pr-closes` RECORD, which is minted by a `[[recorder]]` over a `gh pr view` Bash call, and this environment has no `gh` CLI — so the evidence channel is unavailable rather than unsatisfied, and I will not fabricate a tool result to mint it. Two further facts found while establishing that: the record was also STALE, still naming CLOUD-1269/CLOUD-1279 from the PR this branch carried before it was reset, because `record_path` is branch-keyed with no PR identity; and removing that stale line does not exempt either, since the predicate needs a positive record rather than an absent one. R-FIX-IT-HERE does not apply because there is nothing to fix — the row is not a punt. R-FILE-IT-AFTER-LANDING would land the mechanism with its own reasoning unrecorded, which is the failure the row exists to prevent.
Weakens: program-changed program[land-lock-status]
Weakens: program-changed program[land-lock-peek]
Weakens: recorder-added recorder[landing-lease]
wenzowski added a commit that referenced this pull request Sep 2, 2026
…e alone

A branch NAME outlives the branch it described. `git checkout -B <name>
origin/main` discards the commits that were the branch while every name-keyed
file survives — CLOUD-516's finding, which the claim receipt already answers
for itself by recording the base it was made against. A `[[recorder]]`'s
record had no such discriminator at all, so the next attempt on a reused
branch name read the previous one's lines as its own.

MEASURED HERE, NOT REASONED ABOUT. After PR #810 merged and this branch was
reset onto the new trunk, `pr-closes.<branch>` still held `closes
2:CLOUD-1269,CLOUD-1279` — that PR's keys. The PR actually open was #812,
closing CLOUD-1298, which appeared nowhere in the record.

THE DANGEROUS DIRECTION IS THE SILENT ONE. `filed-over-own-diff` exempts a row
the PR CLOSES and reads that from this record, so a stale record does not
merely refuse an honest file-then-fix: a row named by the PREVIOUS PR's
closes-record would be EXEMPTED on a PR that does not close it, with nothing
downstream to re-check.

THE CLAIM RATHER THAN THE BASE, and the difference is what makes it usable. A
base moves on every rebase and `land` rebases every lap, so keying a record on
one would discard it mid-landing — the failure this prevents, arriving by
another route. A claim is re-minted per PULL and is stable across every rebase
in between, so it partitions exactly the attempts that must not see each other.

`claimed_token` is order-insensitive over a multi-key claim, or a re-claim of
the same work would partition itself away from its own record. `None` is
could-not-look and keeps the OLD path, which is what makes this a partition
rather than a migration: nothing that could not be attributed is moved, and an
unclaimed branch behaves exactly as before.

THREE READERS, AND THE THIRD IS THE ONE A NARROW FIX MISSES. `append_all`
writes, `recorder_records` projects the tree fact — and `filed-here`'s own
end-of-turn checklist reads the board record directly in `lib.rs`. Without the
same partition there it would list a previous attempt's rows as this one's.

Test obligation: four cases over the compiled binary, driving `batten hook`
twice under two claims on one branch name. The false-exemption case is the one
a naive suite misses, so it is written first and asserts the ABSENCE of the
previous attempt's key; its anti-vacuity mirror proves one claim still
accumulates across calls, without which the case is satisfied by a partition
so eager that no record survives a lap at all.

Refs: CLOUD-1300
Refs: CLOUD-516
wenzowski added a commit that referenced this pull request Sep 2, 2026
CLOUD-1280 landed `lease-authorises-the-branch` and this repository declared no
`[[recorder]]` writing a lease line, so `input.tree.records` carried none and
the predicate allowed unconditionally. Fail-open rather than a dead gate — the
refusal it could not reach is the refusal it is designed not to reach — but
every reading of it was a test fixture, which is the one thing CLOUD-1269 calls
"the only way the surface gets exercised by something other than its own tests."

Three non-obvious choices, each PROBED rather than assumed:

  * `status`, not `authorises`. The `authorises` arm answers the module's exact
    question and takes the branch on ARGV; `Program::args` is a fixed
    `Vec<String>` frozen at config load, so a row could only hard-code one
    branch forever. `status` takes none.
  * `peek next`, not `peek`. `peek` with no field argument is exit 2 with 51
    bytes of USAGE TEXT on stdout, and `render_column` folds whitespace — so the
    record's shape survives and the successor column silently carries prose that
    can never equal a branch. That is a fail-CLOSED deviation on the one row
    `Value::Branch` exists to keep open, and it was live in the first draft.
  * `2` is deliberately unmapped in the `status` table. `status` fails closed
    where it cannot observe the lease; `authorises` fails open. An unmapped
    status records could-not-look, which equals neither token, so the refusal
    cannot hold. The OMISSION is what restores the asymmetry at the boundary —
    adding a `"2"` row inverts the one behaviour the port exists to conserve.

THE ORDERING BOUND, STATED WHERE THE ROW LIVES. A recorder writes on the
post-tool event, and `mise run land` runs its whole lap inside ONE Bash call, so
nothing is written while a lap runs and the line `batten check` reads is
whatever the call before `land` left. `linear-check` is the step the contract
puts immediately before `land`, which makes the reading seconds old rather than
a lap old. On lap 2 and after nothing refreshes it, so a lease a rival acquired
during lap 1 is not seen — under-denying, which is the sanctioned direction for
a predicate whose whole asymmetry is that a reading it could not take allows.

The wide selector was priced and rejected: every Bash call would keep the record
always-fresh and put a remote lease observation on the mediated path of every
call, which `perf-assert` budgets against. `satisfied` is evaluated before any
column, so a narrow selector spawns nothing on an ordinary call — asserted, not
assumed, by the selector's own anti-vacuity case.

Test obligation: seven cases over the compiled binary in
`crates/batten/tests/it/lease_record.rs`, driving `batten hook` and reading the
file back. The preset suite structurally cannot be this tier — a `with input as`
case fabricates the very line the engine may be unable to write. The
could-not-look case asserts the recorded TOKEN rather than the file's existence,
because a case reading only the file would pass over a table that mapped `2`.

Weakens: recorder-added recorder[landing-lease]

Refs: CLOUD-1298
Refs: CLOUD-1269

Admits: 8b8119b1795d43416aa547233174231a5a75e42828d43440f3df535ee5befaf3
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: cb33679
Admits-epoch: 8ae3d03b504fed658464f45a75ce2f4963f458a806777852c084456400109939
Admits-author: alec@wenzowski.com
Admits-prev: 8dcfee86e3267762a0716a9cfbc1fba755289534cd5c298c11265497f3f2e93d
Admits-answer-lost: Without the recorder the preset predicate merged in #810 has no record to read, so `input.tree.records` carries no lease line and the predicate allows unconditionally. That is the fail-open direction and so not a dead gate in CLOUD-845's sense, but it means consumer #1 does not eat its own food — the clause CLOUD-1269 names as "the only way the surface gets exercised by something other than its own tests" — and a landing lap keeps spending CI against a lease nothing in the engine reads.
Admits-answer-precondition: `batten.toml` IS the owning surface for a `[[recorder]]`, a `[program]` and a `[[pattern]]` row: it is the one authority the engine reads for all three, so a recorder that writes the landing-lease record cannot be declared anywhere else. This adds the row that makes `lease-authorises-the-branch` non-decorative in this repository, and it lands in a PR diff a reviewer sees.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is circular for this subject, because `batten.toml` IS the owning surface for a recorder, a program and a pattern row — no other file the engine consults declares one. R-RESTORE-IT would revert the rows and leave the predicate reading a record nothing writes.

Admits: c90a5c16aadfea21155819bed70c8150b24134cc025a3b2728a7b836ef5e9e83
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: cb33679
Admits-epoch: d900ba911dec5d109316dc19515aded5283414e1bf481ca30fa363aec876a210
Admits-author: alec@wenzowski.com
Admits-prev: 8b8119b1795d43416aa547233174231a5a75e42828d43440f3df535ee5befaf3
Admits-answer-lost: Without the recorder the preset predicate merged in #810 has no record to read, so `input.tree.records` carries no lease line and the predicate allows unconditionally. Fail-open, so not a dead gate in CLOUD-845's sense, but consumer #1 then does not eat its own food — the clause CLOUD-1269 calls "the only way the surface gets exercised by something other than its own tests" — and a landing lap keeps spending CI against a lease nothing in the engine reads.
Admits-answer-precondition: `batten.toml` IS the owning surface for a `[[recorder]]` and a `[[pattern]]` row: it is the one authority the engine reads for both, so the recorder that writes the landing-lease record and the selector it narrows on cannot be declared anywhere else. They are one block in one edit because an admission is single-use and the two rows are one mechanism. It lands in a PR diff a reviewer sees.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is circular for this subject, because `batten.toml` IS the owning surface for a recorder and a pattern row — no other file the engine consults declares either. R-RESTORE-IT would revert the block and leave the predicate reading a record nothing writes.

Admits: d7b0aaf76565dfa1a3ca87a2a2454c0e210bd854260e69f2bcebcd506ad4b28b
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: cb33679
Admits-epoch: 8a8bfc7d345f36b6d4d97458d63cf6aecb8216a100325631b4243c7a240efca3
Admits-author: alec@wenzowski.com
Admits-prev: c90a5c16aadfea21155819bed70c8150b24134cc025a3b2728a7b836ef5e9e83
Admits-answer-lost: Without the fix the successor column records a usage-error string on every write. `render_column` folds whitespace so the record SHAPE survives, which is what makes this silent: the module compares that string against the branch, finds them unequal, and the refusal stands. That is a fail-CLOSED deviation on the admitted-successor row — precisely the laundering CLOUD-1269 forbids and the exact case `Value::Branch` was added to prevent.
Admits-answer-precondition: `batten.toml` IS the owning surface for a `[program]` row, so the argv a recorder column runs cannot be corrected anywhere else. This fixes a defect in the block admitted moments ago: `land-lock peek` REQUIRES a field argument and the row omitted it, so the program exited 2 and wrote a usage line to stdout that the column would have recorded as the successor. Probed directly — `peek` alone is exit 2 with 51 bytes of usage text, `peek next` is exit 0 and empty. It lands in a PR diff a reviewer sees.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is circular for this subject, because `batten.toml` IS the owning surface for a `[program]` row's argv — no other file the engine consults declares one. R-RESTORE-IT would restore the argv-less invocation and reinstate the fail-closed successor row.
wenzowski added a commit that referenced this pull request Sep 2, 2026
`filed-over-own-diff` refuses `batten.toml` on this branch, and the route its
own class declares — R-CLOSE-IT-IN-THE-BODY — is the one taken: PR #812's body
opens with `Closes CLOUD-1298`. The gate cannot see it, and the reason is a
mechanism gap rather than an unmet condition.

The exemption reads the `pr-closes` RECORD, minted by a `[[recorder]]` over a
`gh pr view` Bash call. This environment has no `gh`, so the evidence channel is
unavailable — and fabricating a tool result to mint the record would forge the
very evidence the exemption exists to demand.

TWO FURTHER FACTS, FOUND WHILE ESTABLISHING THAT, AND THE FIRST IS A DEFECT:

  * The record was STALE, still naming CLOUD-1269 and CLOUD-1279 from the PR
    this branch carried before it was reset onto the merged trunk.
    `record_path` is branch-keyed with no PR identity, so a reused branch name
    inherits the previous PR's closes-record and the exemption then reads the
    wrong PR's keys. Same family as the lease record's history bound one level
    up: no per-PR partition.
  * Removing that stale line does not exempt either. The predicate needs a
    POSITIVE record naming the key, so an absent channel refuses where an
    absent finding would have passed.

Admits: e8a1d7bfdb26149ed897edccf84b90248b37b2f15ac077991be687da6d75f0f8
Admits-rule: filed-here
Admits-verdict: V-FILED-OVER-OWN-DIFF
Admits-subject: batten.toml
Admits-head: 717afda
Admits-epoch: c4d86ca484c6cc808f9252e1394b9ad10993d6646fdcf5864522e2af3d23a020
Admits-author: alec@wenzowski.com
Admits-prev: -
Admits-answer-lost: Nothing is deferred, so the toll prices a punt that did not happen. Paying it any other way means either not filing the row — leaving the wiring's ordering bound, its rejected wide-selector alternative and its `peek next` defect recorded nowhere — or splitting the file from the fix across two branches, which is the batching this repository's whole trunk discipline exists to prevent.
Admits-answer-precondition: CLOUD-1298 DOCUMENTS this change rather than deferring it. Its §1 names `batten.toml` because `batten.toml` is what the change edits — the two `[program]` rows, the `[[pattern]]` and the `[[recorder]]` that make #810's landed predicate read something real. The row was filed and fixed in the same branch, and the fix is in this diff.
Admits-answer-rejected-route: R-CLOSE-IT-IN-THE-BODY IS THE ROUTE I TOOK, and the override is only because the gate cannot see it. PR #812's body opens with `Closes CLOUD-1298`. The exemption reads the `pr-closes` RECORD, which is minted by a `[[recorder]]` over a `gh pr view` Bash call, and this environment has no `gh` CLI — so the evidence channel is unavailable rather than unsatisfied, and I will not fabricate a tool result to mint it. Two further facts found while establishing that: the record was also STALE, still naming CLOUD-1269/CLOUD-1279 from the PR this branch carried before it was reset, because `record_path` is branch-keyed with no PR identity; and removing that stale line does not exempt either, since the predicate needs a positive record rather than an absent one. R-FIX-IT-HERE does not apply because there is nothing to fix — the row is not a punt. R-FILE-IT-AFTER-LANDING would land the mechanism with its own reasoning unrecorded, which is the failure the row exists to prevent.
Weakens: program-changed program[land-lock-status]
Weakens: program-changed program[land-lock-peek]
Weakens: recorder-added recorder[landing-lease]
wenzowski added a commit that referenced this pull request Sep 2, 2026
…e alone

A branch NAME outlives the branch it described. `git checkout -B <name>
origin/main` discards the commits that were the branch while every name-keyed
file survives — CLOUD-516's finding, which the claim receipt already answers
for itself by recording the base it was made against. A `[[recorder]]`'s
record had no such discriminator at all, so the next attempt on a reused
branch name read the previous one's lines as its own.

MEASURED HERE, NOT REASONED ABOUT. After PR #810 merged and this branch was
reset onto the new trunk, `pr-closes.<branch>` still held `closes
2:CLOUD-1269,CLOUD-1279` — that PR's keys. The PR actually open was #812,
closing CLOUD-1298, which appeared nowhere in the record.

THE DANGEROUS DIRECTION IS THE SILENT ONE. `filed-over-own-diff` exempts a row
the PR CLOSES and reads that from this record, so a stale record does not
merely refuse an honest file-then-fix: a row named by the PREVIOUS PR's
closes-record would be EXEMPTED on a PR that does not close it, with nothing
downstream to re-check.

THE CLAIM RATHER THAN THE BASE, and the difference is what makes it usable. A
base moves on every rebase and `land` rebases every lap, so keying a record on
one would discard it mid-landing — the failure this prevents, arriving by
another route. A claim is re-minted per PULL and is stable across every rebase
in between, so it partitions exactly the attempts that must not see each other.

`claimed_token` is order-insensitive over a multi-key claim, or a re-claim of
the same work would partition itself away from its own record. `None` is
could-not-look and keeps the OLD path, which is what makes this a partition
rather than a migration: nothing that could not be attributed is moved, and an
unclaimed branch behaves exactly as before.

THREE READERS, AND THE THIRD IS THE ONE A NARROW FIX MISSES. `append_all`
writes, `recorder_records` projects the tree fact — and `filed-here`'s own
end-of-turn checklist reads the board record directly in `lib.rs`. Without the
same partition there it would list a previous attempt's rows as this one's.

Test obligation: four cases over the compiled binary, driving `batten hook`
twice under two claims on one branch name. The false-exemption case is the one
a naive suite misses, so it is written first and asserts the ABSENCE of the
previous attempt's key; its anti-vacuity mirror proves one claim still
accumulates across calls, without which the case is satisfied by a partition
so eager that no record survives a lap at all.

Refs: CLOUD-1300
Refs: CLOUD-516
wenzowski added a commit that referenced this pull request Sep 2, 2026
CLOUD-1280 landed `lease-authorises-the-branch` and this repository declared no
`[[recorder]]` writing a lease line, so `input.tree.records` carried none and
the predicate allowed unconditionally. Fail-open rather than a dead gate — the
refusal it could not reach is the refusal it is designed not to reach — but
every reading of it was a test fixture, which is the one thing CLOUD-1269 calls
"the only way the surface gets exercised by something other than its own tests."

Three non-obvious choices, each PROBED rather than assumed:

  * `status`, not `authorises`. The `authorises` arm answers the module's exact
    question and takes the branch on ARGV; `Program::args` is a fixed
    `Vec<String>` frozen at config load, so a row could only hard-code one
    branch forever. `status` takes none.
  * `peek next`, not `peek`. `peek` with no field argument is exit 2 with 51
    bytes of USAGE TEXT on stdout, and `render_column` folds whitespace — so the
    record's shape survives and the successor column silently carries prose that
    can never equal a branch. That is a fail-CLOSED deviation on the one row
    `Value::Branch` exists to keep open, and it was live in the first draft.
  * `2` is deliberately unmapped in the `status` table. `status` fails closed
    where it cannot observe the lease; `authorises` fails open. An unmapped
    status records could-not-look, which equals neither token, so the refusal
    cannot hold. The OMISSION is what restores the asymmetry at the boundary —
    adding a `"2"` row inverts the one behaviour the port exists to conserve.

THE ORDERING BOUND, STATED WHERE THE ROW LIVES. A recorder writes on the
post-tool event, and `mise run land` runs its whole lap inside ONE Bash call, so
nothing is written while a lap runs and the line `batten check` reads is
whatever the call before `land` left. `linear-check` is the step the contract
puts immediately before `land`, which makes the reading seconds old rather than
a lap old. On lap 2 and after nothing refreshes it, so a lease a rival acquired
during lap 1 is not seen — under-denying, which is the sanctioned direction for
a predicate whose whole asymmetry is that a reading it could not take allows.

The wide selector was priced and rejected: every Bash call would keep the record
always-fresh and put a remote lease observation on the mediated path of every
call, which `perf-assert` budgets against. `satisfied` is evaluated before any
column, so a narrow selector spawns nothing on an ordinary call — asserted, not
assumed, by the selector's own anti-vacuity case.

Test obligation: seven cases over the compiled binary in
`crates/batten/tests/it/lease_record.rs`, driving `batten hook` and reading the
file back. The preset suite structurally cannot be this tier — a `with input as`
case fabricates the very line the engine may be unable to write. The
could-not-look case asserts the recorded TOKEN rather than the file's existence,
because a case reading only the file would pass over a table that mapped `2`.

Weakens: recorder-added recorder[landing-lease]

Refs: CLOUD-1298
Refs: CLOUD-1269

Admits: 8b8119b1795d43416aa547233174231a5a75e42828d43440f3df535ee5befaf3
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: cb33679
Admits-epoch: 8ae3d03b504fed658464f45a75ce2f4963f458a806777852c084456400109939
Admits-author: alec@wenzowski.com
Admits-prev: 8dcfee86e3267762a0716a9cfbc1fba755289534cd5c298c11265497f3f2e93d
Admits-answer-lost: Without the recorder the preset predicate merged in #810 has no record to read, so `input.tree.records` carries no lease line and the predicate allows unconditionally. That is the fail-open direction and so not a dead gate in CLOUD-845's sense, but it means consumer #1 does not eat its own food — the clause CLOUD-1269 names as "the only way the surface gets exercised by something other than its own tests" — and a landing lap keeps spending CI against a lease nothing in the engine reads.
Admits-answer-precondition: `batten.toml` IS the owning surface for a `[[recorder]]`, a `[program]` and a `[[pattern]]` row: it is the one authority the engine reads for all three, so a recorder that writes the landing-lease record cannot be declared anywhere else. This adds the row that makes `lease-authorises-the-branch` non-decorative in this repository, and it lands in a PR diff a reviewer sees.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is circular for this subject, because `batten.toml` IS the owning surface for a recorder, a program and a pattern row — no other file the engine consults declares one. R-RESTORE-IT would revert the rows and leave the predicate reading a record nothing writes.

Admits: c90a5c16aadfea21155819bed70c8150b24134cc025a3b2728a7b836ef5e9e83
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: cb33679
Admits-epoch: d900ba911dec5d109316dc19515aded5283414e1bf481ca30fa363aec876a210
Admits-author: alec@wenzowski.com
Admits-prev: 8b8119b1795d43416aa547233174231a5a75e42828d43440f3df535ee5befaf3
Admits-answer-lost: Without the recorder the preset predicate merged in #810 has no record to read, so `input.tree.records` carries no lease line and the predicate allows unconditionally. Fail-open, so not a dead gate in CLOUD-845's sense, but consumer #1 then does not eat its own food — the clause CLOUD-1269 calls "the only way the surface gets exercised by something other than its own tests" — and a landing lap keeps spending CI against a lease nothing in the engine reads.
Admits-answer-precondition: `batten.toml` IS the owning surface for a `[[recorder]]` and a `[[pattern]]` row: it is the one authority the engine reads for both, so the recorder that writes the landing-lease record and the selector it narrows on cannot be declared anywhere else. They are one block in one edit because an admission is single-use and the two rows are one mechanism. It lands in a PR diff a reviewer sees.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is circular for this subject, because `batten.toml` IS the owning surface for a recorder and a pattern row — no other file the engine consults declares either. R-RESTORE-IT would revert the block and leave the predicate reading a record nothing writes.

Admits: d7b0aaf76565dfa1a3ca87a2a2454c0e210bd854260e69f2bcebcd506ad4b28b
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: cb33679
Admits-epoch: 8a8bfc7d345f36b6d4d97458d63cf6aecb8216a100325631b4243c7a240efca3
Admits-author: alec@wenzowski.com
Admits-prev: c90a5c16aadfea21155819bed70c8150b24134cc025a3b2728a7b836ef5e9e83
Admits-answer-lost: Without the fix the successor column records a usage-error string on every write. `render_column` folds whitespace so the record SHAPE survives, which is what makes this silent: the module compares that string against the branch, finds them unequal, and the refusal stands. That is a fail-CLOSED deviation on the admitted-successor row — precisely the laundering CLOUD-1269 forbids and the exact case `Value::Branch` was added to prevent.
Admits-answer-precondition: `batten.toml` IS the owning surface for a `[program]` row, so the argv a recorder column runs cannot be corrected anywhere else. This fixes a defect in the block admitted moments ago: `land-lock peek` REQUIRES a field argument and the row omitted it, so the program exited 2 and wrote a usage line to stdout that the column would have recorded as the successor. Probed directly — `peek` alone is exit 2 with 51 bytes of usage text, `peek next` is exit 0 and empty. It lands in a PR diff a reviewer sees.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is circular for this subject, because `batten.toml` IS the owning surface for a `[program]` row's argv — no other file the engine consults declares one. R-RESTORE-IT would restore the argv-less invocation and reinstate the fail-closed successor row.
wenzowski added a commit that referenced this pull request Sep 2, 2026
`filed-over-own-diff` refuses `batten.toml` on this branch, and the route its
own class declares — R-CLOSE-IT-IN-THE-BODY — is the one taken: PR #812's body
opens with `Closes CLOUD-1298`. The gate cannot see it, and the reason is a
mechanism gap rather than an unmet condition.

The exemption reads the `pr-closes` RECORD, minted by a `[[recorder]]` over a
`gh pr view` Bash call. This environment has no `gh`, so the evidence channel is
unavailable — and fabricating a tool result to mint the record would forge the
very evidence the exemption exists to demand.

TWO FURTHER FACTS, FOUND WHILE ESTABLISHING THAT, AND THE FIRST IS A DEFECT:

  * The record was STALE, still naming CLOUD-1269 and CLOUD-1279 from the PR
    this branch carried before it was reset onto the merged trunk.
    `record_path` is branch-keyed with no PR identity, so a reused branch name
    inherits the previous PR's closes-record and the exemption then reads the
    wrong PR's keys. Same family as the lease record's history bound one level
    up: no per-PR partition.
  * Removing that stale line does not exempt either. The predicate needs a
    POSITIVE record naming the key, so an absent channel refuses where an
    absent finding would have passed.

Admits: e8a1d7bfdb26149ed897edccf84b90248b37b2f15ac077991be687da6d75f0f8
Admits-rule: filed-here
Admits-verdict: V-FILED-OVER-OWN-DIFF
Admits-subject: batten.toml
Admits-head: 717afda
Admits-epoch: c4d86ca484c6cc808f9252e1394b9ad10993d6646fdcf5864522e2af3d23a020
Admits-author: alec@wenzowski.com
Admits-prev: -
Admits-answer-lost: Nothing is deferred, so the toll prices a punt that did not happen. Paying it any other way means either not filing the row — leaving the wiring's ordering bound, its rejected wide-selector alternative and its `peek next` defect recorded nowhere — or splitting the file from the fix across two branches, which is the batching this repository's whole trunk discipline exists to prevent.
Admits-answer-precondition: CLOUD-1298 DOCUMENTS this change rather than deferring it. Its §1 names `batten.toml` because `batten.toml` is what the change edits — the two `[program]` rows, the `[[pattern]]` and the `[[recorder]]` that make #810's landed predicate read something real. The row was filed and fixed in the same branch, and the fix is in this diff.
Admits-answer-rejected-route: R-CLOSE-IT-IN-THE-BODY IS THE ROUTE I TOOK, and the override is only because the gate cannot see it. PR #812's body opens with `Closes CLOUD-1298`. The exemption reads the `pr-closes` RECORD, which is minted by a `[[recorder]]` over a `gh pr view` Bash call, and this environment has no `gh` CLI — so the evidence channel is unavailable rather than unsatisfied, and I will not fabricate a tool result to mint it. Two further facts found while establishing that: the record was also STALE, still naming CLOUD-1269/CLOUD-1279 from the PR this branch carried before it was reset, because `record_path` is branch-keyed with no PR identity; and removing that stale line does not exempt either, since the predicate needs a positive record rather than an absent one. R-FIX-IT-HERE does not apply because there is nothing to fix — the row is not a punt. R-FILE-IT-AFTER-LANDING would land the mechanism with its own reasoning unrecorded, which is the failure the row exists to prevent.
Weakens: program-changed program[land-lock-status]
Weakens: program-changed program[land-lock-peek]
Weakens: recorder-added recorder[landing-lease]
wenzowski added a commit that referenced this pull request Sep 2, 2026
…e alone

A branch NAME outlives the branch it described. `git checkout -B <name>
origin/main` discards the commits that were the branch while every name-keyed
file survives — CLOUD-516's finding, which the claim receipt already answers
for itself by recording the base it was made against. A `[[recorder]]`'s
record had no such discriminator at all, so the next attempt on a reused
branch name read the previous one's lines as its own.

MEASURED HERE, NOT REASONED ABOUT. After PR #810 merged and this branch was
reset onto the new trunk, `pr-closes.<branch>` still held `closes
2:CLOUD-1269,CLOUD-1279` — that PR's keys. The PR actually open was #812,
closing CLOUD-1298, which appeared nowhere in the record.

THE DANGEROUS DIRECTION IS THE SILENT ONE. `filed-over-own-diff` exempts a row
the PR CLOSES and reads that from this record, so a stale record does not
merely refuse an honest file-then-fix: a row named by the PREVIOUS PR's
closes-record would be EXEMPTED on a PR that does not close it, with nothing
downstream to re-check.

THE CLAIM RATHER THAN THE BASE, and the difference is what makes it usable. A
base moves on every rebase and `land` rebases every lap, so keying a record on
one would discard it mid-landing — the failure this prevents, arriving by
another route. A claim is re-minted per PULL and is stable across every rebase
in between, so it partitions exactly the attempts that must not see each other.

`claimed_token` is order-insensitive over a multi-key claim, or a re-claim of
the same work would partition itself away from its own record. `None` is
could-not-look and keeps the OLD path, which is what makes this a partition
rather than a migration: nothing that could not be attributed is moved, and an
unclaimed branch behaves exactly as before.

THREE READERS, AND THE THIRD IS THE ONE A NARROW FIX MISSES. `append_all`
writes, `recorder_records` projects the tree fact — and `filed-here`'s own
end-of-turn checklist reads the board record directly in `lib.rs`. Without the
same partition there it would list a previous attempt's rows as this one's.

Test obligation: four cases over the compiled binary, driving `batten hook`
twice under two claims on one branch name. The false-exemption case is the one
a naive suite misses, so it is written first and asserts the ABSENCE of the
previous attempt's key; its anti-vacuity mirror proves one claim still
accumulates across calls, without which the case is satisfied by a partition
so eager that no record survives a lap at all.

Refs: CLOUD-1300
Refs: CLOUD-516
wenzowski added a commit that referenced this pull request Sep 2, 2026
CLOUD-1280 landed `lease-authorises-the-branch` and this repository declared no
`[[recorder]]` writing a lease line, so `input.tree.records` carried none and
the predicate allowed unconditionally. Fail-open rather than a dead gate — the
refusal it could not reach is the refusal it is designed not to reach — but
every reading of it was a test fixture, which is the one thing CLOUD-1269 calls
"the only way the surface gets exercised by something other than its own tests."

Three non-obvious choices, each PROBED rather than assumed:

  * `status`, not `authorises`. The `authorises` arm answers the module's exact
    question and takes the branch on ARGV; `Program::args` is a fixed
    `Vec<String>` frozen at config load, so a row could only hard-code one
    branch forever. `status` takes none.
  * `peek next`, not `peek`. `peek` with no field argument is exit 2 with 51
    bytes of USAGE TEXT on stdout, and `render_column` folds whitespace — so the
    record's shape survives and the successor column silently carries prose that
    can never equal a branch. That is a fail-CLOSED deviation on the one row
    `Value::Branch` exists to keep open, and it was live in the first draft.
  * `2` is deliberately unmapped in the `status` table. `status` fails closed
    where it cannot observe the lease; `authorises` fails open. An unmapped
    status records could-not-look, which equals neither token, so the refusal
    cannot hold. The OMISSION is what restores the asymmetry at the boundary —
    adding a `"2"` row inverts the one behaviour the port exists to conserve.

THE ORDERING BOUND, STATED WHERE THE ROW LIVES. A recorder writes on the
post-tool event, and `mise run land` runs its whole lap inside ONE Bash call, so
nothing is written while a lap runs and the line `batten check` reads is
whatever the call before `land` left. `linear-check` is the step the contract
puts immediately before `land`, which makes the reading seconds old rather than
a lap old. On lap 2 and after nothing refreshes it, so a lease a rival acquired
during lap 1 is not seen — under-denying, which is the sanctioned direction for
a predicate whose whole asymmetry is that a reading it could not take allows.

The wide selector was priced and rejected: every Bash call would keep the record
always-fresh and put a remote lease observation on the mediated path of every
call, which `perf-assert` budgets against. `satisfied` is evaluated before any
column, so a narrow selector spawns nothing on an ordinary call — asserted, not
assumed, by the selector's own anti-vacuity case.

Test obligation: seven cases over the compiled binary in
`crates/batten/tests/it/lease_record.rs`, driving `batten hook` and reading the
file back. The preset suite structurally cannot be this tier — a `with input as`
case fabricates the very line the engine may be unable to write. The
could-not-look case asserts the recorded TOKEN rather than the file's existence,
because a case reading only the file would pass over a table that mapped `2`.

Weakens: recorder-added recorder[landing-lease]

Refs: CLOUD-1298
Refs: CLOUD-1269

Admits: 8b8119b1795d43416aa547233174231a5a75e42828d43440f3df535ee5befaf3
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: cb33679
Admits-epoch: 8ae3d03b504fed658464f45a75ce2f4963f458a806777852c084456400109939
Admits-author: alec@wenzowski.com
Admits-prev: 8dcfee86e3267762a0716a9cfbc1fba755289534cd5c298c11265497f3f2e93d
Admits-answer-lost: Without the recorder the preset predicate merged in #810 has no record to read, so `input.tree.records` carries no lease line and the predicate allows unconditionally. That is the fail-open direction and so not a dead gate in CLOUD-845's sense, but it means consumer #1 does not eat its own food — the clause CLOUD-1269 names as "the only way the surface gets exercised by something other than its own tests" — and a landing lap keeps spending CI against a lease nothing in the engine reads.
Admits-answer-precondition: `batten.toml` IS the owning surface for a `[[recorder]]`, a `[program]` and a `[[pattern]]` row: it is the one authority the engine reads for all three, so a recorder that writes the landing-lease record cannot be declared anywhere else. This adds the row that makes `lease-authorises-the-branch` non-decorative in this repository, and it lands in a PR diff a reviewer sees.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is circular for this subject, because `batten.toml` IS the owning surface for a recorder, a program and a pattern row — no other file the engine consults declares one. R-RESTORE-IT would revert the rows and leave the predicate reading a record nothing writes.

Admits: c90a5c16aadfea21155819bed70c8150b24134cc025a3b2728a7b836ef5e9e83
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: cb33679
Admits-epoch: d900ba911dec5d109316dc19515aded5283414e1bf481ca30fa363aec876a210
Admits-author: alec@wenzowski.com
Admits-prev: 8b8119b1795d43416aa547233174231a5a75e42828d43440f3df535ee5befaf3
Admits-answer-lost: Without the recorder the preset predicate merged in #810 has no record to read, so `input.tree.records` carries no lease line and the predicate allows unconditionally. Fail-open, so not a dead gate in CLOUD-845's sense, but consumer #1 then does not eat its own food — the clause CLOUD-1269 calls "the only way the surface gets exercised by something other than its own tests" — and a landing lap keeps spending CI against a lease nothing in the engine reads.
Admits-answer-precondition: `batten.toml` IS the owning surface for a `[[recorder]]` and a `[[pattern]]` row: it is the one authority the engine reads for both, so the recorder that writes the landing-lease record and the selector it narrows on cannot be declared anywhere else. They are one block in one edit because an admission is single-use and the two rows are one mechanism. It lands in a PR diff a reviewer sees.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is circular for this subject, because `batten.toml` IS the owning surface for a recorder and a pattern row — no other file the engine consults declares either. R-RESTORE-IT would revert the block and leave the predicate reading a record nothing writes.

Admits: d7b0aaf76565dfa1a3ca87a2a2454c0e210bd854260e69f2bcebcd506ad4b28b
Admits-rule: protected-mutation
Admits-verdict: V-PROTECTED-MUTATION
Admits-subject: batten.toml
Admits-head: cb33679
Admits-epoch: 8a8bfc7d345f36b6d4d97458d63cf6aecb8216a100325631b4243c7a240efca3
Admits-author: alec@wenzowski.com
Admits-prev: c90a5c16aadfea21155819bed70c8150b24134cc025a3b2728a7b836ef5e9e83
Admits-answer-lost: Without the fix the successor column records a usage-error string on every write. `render_column` folds whitespace so the record SHAPE survives, which is what makes this silent: the module compares that string against the branch, finds them unequal, and the refusal stands. That is a fail-CLOSED deviation on the admitted-successor row — precisely the laundering CLOUD-1269 forbids and the exact case `Value::Branch` was added to prevent.
Admits-answer-precondition: `batten.toml` IS the owning surface for a `[program]` row, so the argv a recorder column runs cannot be corrected anywhere else. This fixes a defect in the block admitted moments ago: `land-lock peek` REQUIRES a field argument and the row omitted it, so the program exited 2 and wrote a usage line to stdout that the column would have recorded as the successor. Probed directly — `peek` alone is exit 2 with 51 bytes of usage text, `peek next` is exit 0 and empty. It lands in a PR diff a reviewer sees.
Admits-answer-rejected-route: R-USE-THE-OWNING-SURFACE is circular for this subject, because `batten.toml` IS the owning surface for a `[program]` row's argv — no other file the engine consults declares one. R-RESTORE-IT would restore the argv-less invocation and reinstate the fail-closed successor row.
wenzowski added a commit that referenced this pull request Sep 2, 2026
`filed-over-own-diff` refuses `batten.toml` on this branch, and the route its
own class declares — R-CLOSE-IT-IN-THE-BODY — is the one taken: PR #812's body
opens with `Closes CLOUD-1298`. The gate cannot see it, and the reason is a
mechanism gap rather than an unmet condition.

The exemption reads the `pr-closes` RECORD, minted by a `[[recorder]]` over a
`gh pr view` Bash call. This environment has no `gh`, so the evidence channel is
unavailable — and fabricating a tool result to mint the record would forge the
very evidence the exemption exists to demand.

TWO FURTHER FACTS, FOUND WHILE ESTABLISHING THAT, AND THE FIRST IS A DEFECT:

  * The record was STALE, still naming CLOUD-1269 and CLOUD-1279 from the PR
    this branch carried before it was reset onto the merged trunk.
    `record_path` is branch-keyed with no PR identity, so a reused branch name
    inherits the previous PR's closes-record and the exemption then reads the
    wrong PR's keys. Same family as the lease record's history bound one level
    up: no per-PR partition.
  * Removing that stale line does not exempt either. The predicate needs a
    POSITIVE record naming the key, so an absent channel refuses where an
    absent finding would have passed.

Admits: e8a1d7bfdb26149ed897edccf84b90248b37b2f15ac077991be687da6d75f0f8
Admits-rule: filed-here
Admits-verdict: V-FILED-OVER-OWN-DIFF
Admits-subject: batten.toml
Admits-head: 717afda
Admits-epoch: c4d86ca484c6cc808f9252e1394b9ad10993d6646fdcf5864522e2af3d23a020
Admits-author: alec@wenzowski.com
Admits-prev: -
Admits-answer-lost: Nothing is deferred, so the toll prices a punt that did not happen. Paying it any other way means either not filing the row — leaving the wiring's ordering bound, its rejected wide-selector alternative and its `peek next` defect recorded nowhere — or splitting the file from the fix across two branches, which is the batching this repository's whole trunk discipline exists to prevent.
Admits-answer-precondition: CLOUD-1298 DOCUMENTS this change rather than deferring it. Its §1 names `batten.toml` because `batten.toml` is what the change edits — the two `[program]` rows, the `[[pattern]]` and the `[[recorder]]` that make #810's landed predicate read something real. The row was filed and fixed in the same branch, and the fix is in this diff.
Admits-answer-rejected-route: R-CLOSE-IT-IN-THE-BODY IS THE ROUTE I TOOK, and the override is only because the gate cannot see it. PR #812's body opens with `Closes CLOUD-1298`. The exemption reads the `pr-closes` RECORD, which is minted by a `[[recorder]]` over a `gh pr view` Bash call, and this environment has no `gh` CLI — so the evidence channel is unavailable rather than unsatisfied, and I will not fabricate a tool result to mint it. Two further facts found while establishing that: the record was also STALE, still naming CLOUD-1269/CLOUD-1279 from the PR this branch carried before it was reset, because `record_path` is branch-keyed with no PR identity; and removing that stale line does not exempt either, since the predicate needs a positive record rather than an absent one. R-FIX-IT-HERE does not apply because there is nothing to fix — the row is not a punt. R-FILE-IT-AFTER-LANDING would land the mechanism with its own reasoning unrecorded, which is the failure the row exists to prevent.
Weakens: program-changed program[land-lock-status]
Weakens: program-changed program[land-lock-peek]
Weakens: recorder-added recorder[landing-lease]
wenzowski added a commit that referenced this pull request Sep 2, 2026
…e alone

A branch NAME outlives the branch it described. `git checkout -B <name>
origin/main` discards the commits that were the branch while every name-keyed
file survives — CLOUD-516's finding, which the claim receipt already answers
for itself by recording the base it was made against. A `[[recorder]]`'s
record had no such discriminator at all, so the next attempt on a reused
branch name read the previous one's lines as its own.

MEASURED HERE, NOT REASONED ABOUT. After PR #810 merged and this branch was
reset onto the new trunk, `pr-closes.<branch>` still held `closes
2:CLOUD-1269,CLOUD-1279` — that PR's keys. The PR actually open was #812,
closing CLOUD-1298, which appeared nowhere in the record.

THE DANGEROUS DIRECTION IS THE SILENT ONE. `filed-over-own-diff` exempts a row
the PR CLOSES and reads that from this record, so a stale record does not
merely refuse an honest file-then-fix: a row named by the PREVIOUS PR's
closes-record would be EXEMPTED on a PR that does not close it, with nothing
downstream to re-check.

THE CLAIM RATHER THAN THE BASE, and the difference is what makes it usable. A
base moves on every rebase and `land` rebases every lap, so keying a record on
one would discard it mid-landing — the failure this prevents, arriving by
another route. A claim is re-minted per PULL and is stable across every rebase
in between, so it partitions exactly the attempts that must not see each other.

`claimed_token` is order-insensitive over a multi-key claim, or a re-claim of
the same work would partition itself away from its own record. `None` is
could-not-look and keeps the OLD path, which is what makes this a partition
rather than a migration: nothing that could not be attributed is moved, and an
unclaimed branch behaves exactly as before.

THREE READERS, AND THE THIRD IS THE ONE A NARROW FIX MISSES. `append_all`
writes, `recorder_records` projects the tree fact — and `filed-here`'s own
end-of-turn checklist reads the board record directly in `lib.rs`. Without the
same partition there it would list a previous attempt's rows as this one's.

Test obligation: four cases over the compiled binary, driving `batten hook`
twice under two claims on one branch name. The false-exemption case is the one
a naive suite misses, so it is written first and asserts the ABSENCE of the
previous attempt's key; its anti-vacuity mirror proves one claim still
accumulates across calls, without which the case is satisfied by a partition
so eager that no record survives a lap at all.

Refs: CLOUD-1300
Refs: CLOUD-516
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant