Skip to content

fix(land): a speculative lap is judged against the base it borrowed - #1027

Merged
wenzowski merged 1 commit into
mainfrom
claude/cloud-1702-speculative-base-groom
Sep 26, 2026
Merged

wenzowski merged 1 commit into
mainfrom
claude/cloud-1702-speculative-base-groom

Conversation

@wenzowski

Copy link
Copy Markdown
Contributor

Closes CLOUD-1702

This is the defect currently blocking every branch behind the landing lease, including #1025 and #1026.

The premise that speculation breaks

verify:gated arms two gates with a base ref, and both named origin/main unconditionally — on a premise the body states in its own comment:

origin/main is the right base HERE … verify has already refused this branch unless it is rebased on current origin/main, so this task is a function of (commit, current trunk) before this line runs.

That is true of an ordinary lap and false on a speculative one: land replays the branch onto the lease holder's unlanded commits — "the main that is about to exist" — so the tree is a function of (commit, the holder's base). Judging it against trunk charges the holder's diff to the borrower.

Why it refuses rather than just misreporting

lint::groom keys the claim receipt on the branch name. A borrower carries one of its own, minted for its own row and naming no weakening — Groom::Read({}), which is "the groom looked and admitted nothing" and refuses by design (CLOUD-841: evidence of absence, not absence of evidence). The holder's Weakens: trailer cannot admit it, because the borrower's groom has already answered.

commit-lint had the same hole, and its instance is already in this repository's cost record: CLOUD-1775's body tabulates a lap lost to commit-lint — 28 commits "claim no CLOUD-N issue". Those 28 were the holder's.

Measured, not assumed

The change

Both armings become ${BATTEN_SPEC_BASE:-origin/main}. That variable is what land already publishes for exactly this question (speculation::PUBLISHED_AS, CLOUD-748), with land.rs's own a_body_gate_is_told_which_base_the_lap_borrowed asserting it arrives. It is the bound CLOUD-1711 put on race::authored_log, applied to the two gates that still lacked it, and a no-op wherever no bet is live — an ordinary local lap and CI both leave it unset.

Nothing escapes judgement, which is what makes this a fix rather than a relaxation: every commit is still judged once, on its own branch, against the base it actually sits on. The holder's weakenings are adjudicated on the holder's own lap, against trunk, under the holder's groom.

Tests

Two cases in crates/batten/tests/it/verify_unprovisioned.rs, which already owns the reader for this task body:

  • both armed gates read the borrowed base;
  • and both still fall back to trunk — without this, "read BATTEN_SPEC_BASE" is satisfied by dropping the base entirely (the dead-gate class), and a bare $BATTEN_SPEC_BASE would arm config lint with an empty ref off a bet and judge nothing at all.

Shown able to fail: restoring either literal reddens both; with the fix, 17/17 in the suite pass. The first draft of these cases failed for the wrong reason — a bare find for the variable name matched the prose above the arming — so the helper requires the gate invocation on the same line, which is the trap task_body's own comment records one layer up.


Generated by Claude Code

@coderabbitai

coderabbitai Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Warning

Review limit reached

Next included review available in 52 minutes.

Check out review usage here.

View limit details

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

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository: button-inc/batten/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 04255081-bbf2-4f30-9193-efbfaf4e8544

📥 Commits

Reviewing files that changed from the base of the PR and between fc3ed30 and a78419b.

📒 Files selected for processing (2)
  • crates/batten/tests/it/verify_unprovisioned.rs
  • mise.toml

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: button-inc/batten/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 3fc89b9a-b07c-4e92-8bea-06b5d7993d8b

📥 Commits

Reviewing files that changed from the base of the PR and between bb13615 and fc3ed30.

📒 Files selected for processing (2)
  • crates/batten/tests/it/verify_unprovisioned.rs
  • mise.toml

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough
📝 Walkthrough

Priority: ➖ Normal

Merge Risk: ⚪ Minimal · up to fc3ed

No actionable merge-blocking issue is established; the change is mergeable after normal checks.

Security Architecture Review

Security architecture risk: 🔵 Low · up to fc3ed

The change corrects how speculative landings are judged, while ordinary runs retain their existing base. A caller that controls the verification environment can now influence the two local gate comparisons, although the inspected landing path controls that value and CI runs independent checks.

Retained concerns

  • Low · security · inferred: Direct verification-task callers can select the commit range and configuration comparison authority through an unvalidated environment value. This is a local verification-control concern; reachability through the inspected landing and CI paths was not established.
Security review details

Security Blast Radius

  • inferred — The independently attackable surface identified here is a caller-controlled local verification environment, not a demonstrated CI or landing-path bypass. Its immediate outcomes are the two lint verdicts for that invocation.

Security Findings and Attack Paths

  • inferred — A caller supplying BATTEN_SPEC_BASE=HEAD to the direct task can make the commit range empty and select the reviewed tree as config-lint's comparison ref. The inspected validated landing producer and independent CI gates materially limit that scenario; no remotely reachable bypass was established.

Trust Boundaries and Controls

  • observed — The normal landing producer derives publication from bet state rather than an independent value. An integration test confirms that its published environment pair reaches a gate and that an invocation without the pair does not retain it.

Hardening Proposals

  • proposed — If direct verification is intended to attest security policy, bind its base to a validated live bet or a trusted default rather than accepting any ambient BATTEN_SPEC_BASE value. Preserve the independently based CI checks.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: speculative laps are judged against the base they borrowed.
Description check ✅ Passed The description directly explains the defect, the ${BATTEN_SPEC_BASE:-origin/main} change, its fallback behavior, and the added tests.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 1 files. (1 skipped: 1 …
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@wenzowski
wenzowski force-pushed the claude/cloud-1702-speculative-base-groom branch from fc3ed30 to 28b9d37 Compare September 26, 2026 05:47
@wenzowski
wenzowski marked this pull request as ready for review September 26, 2026 05:47
@wenzowski
wenzowski marked this pull request as draft September 26, 2026 05:48
@wenzowski
wenzowski marked this pull request as ready for review September 26, 2026 05:48
`verify:gated` arms two gates with a base ref, and both named `origin/main`
unconditionally on a premise the body states in its own comment: `verify` has
already refused this branch unless it is rebased on current `origin/main`, so the
task is a function of (commit, current trunk).

That premise is false on a speculative lap. `land` replays the branch onto the
lease holder's UNLANDED commits — "the main that is about to exist" — so the tree
is a function of (commit, the holder's base), and judging it against trunk
charges the holder's diff to the BORROWER.

It refuses rather than merely misreporting, which is what made it expensive.
`lint::groom` keys the claim receipt on the branch name, and a borrower carries
one of its own, minted for its own row and naming no weakening: `Groom::Read({})`
is "the groom looked and admitted nothing", a refusal by design (CLOUD-841,
evidence of absence rather than absence of evidence). The holder's `Weakens:`
trailer cannot admit it, because the borrower's groom already answered.

MEASURED 2026-09-25/26, five laps over four different borrowed tips
(`5fa3732a`, `2e6b457e`, `c3315ac6`, `3617f103`), every one refusing
`recorder[board-issue-created] recorder-changed` and its sibling — while
`mise run test:cargo` over the identical integrated commit was 6057/6057 green.
Directly: `BATTEN_CONFIG_FROM=origin/main` gives 2 smells on that tree and
`BATTEN_CONFIG_FROM=3617f103`, the borrowed base, gives 0.

`commit-lint` had the same hole and its instance is already in this repository's
cost record: CLOUD-1775's body tabulates a lap lost to "28 commits claim no
CLOUD-<n> issue". Those 28 were the holder's.

`BATTEN_SPEC_BASE` is what `land` already publishes for exactly this question
(`speculation::PUBLISHED_AS`, CLOUD-748), with `land.rs`'s own
`a_body_gate_is_told_which_base_the_lap_borrowed` asserting it arrives. Reading
it here is the bound CLOUD-1711 put on `race::authored_log`, applied to the two
gates that still lacked it.

NOTHING ESCAPES JUDGEMENT, which is what makes this a fix rather than a
relaxation: every commit is still judged once, on its own branch, against the
base it actually sits on. The holder's weakenings are adjudicated on the holder's
own lap, against trunk, under the holder's groom.

The pair of cases is the pair for a reason. Without the mirror, "read
`BATTEN_SPEC_BASE`" is satisfied by dropping the base entirely — the dead-gate
class — and a bare `$BATTEN_SPEC_BASE` would arm `config lint` with an empty ref
off a bet and judge nothing at all, which is the silence house style §8 arms this
gate against. Both were shown to fail: restoring either literal reddens both.

Refs: CLOUD-1702
@wenzowski
wenzowski force-pushed the claude/cloud-1702-speculative-base-groom branch from 28b9d37 to a78419b Compare September 26, 2026 07:23
@wenzowski

Copy link
Copy Markdown
Contributor Author

/fast-forward

@wenzowski
wenzowski merged commit a78419b into main Sep 26, 2026
14 checks passed
@wenzowski
wenzowski deleted the claude/cloud-1702-speculative-base-groom branch September 26, 2026 07:42
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