Why a pull request triggers runs on stacks it doesn't touch
Last updated: September 10, 2026
Fix: attach the default push policy with the propose { affected } line removed.
Why it happens
Without a push policy, the default starts a proposed run if either rule matches:
affected- checksinput.push.affected_filesaffected_pr- checksinput.pull_request.diff
push.affected_files contains every file touched by every commit in the push, not just the head commit. Rebasing on the tracked branch, merging main into the branch, or pushing a batch of commits all expand that list, so stacks that the final PR diff never touched look affected - and re-trigger on each new commit.
pull_request.diff is the base-to-head diff, i.e. the file list you actually see on the PR.
The policy
Removing propose { affected } leaves affected_pr as the only route to a proposed run:
package spacelift
track if {
affected
input.push.branch == input.stack.branch
}
# Proposed runs come from the PR diff only, not the full push file list.
propose if affected_pr
ignore if {
not affected
not affected_pr
}
ignore if input.push.tag != ""
affected if {
some filepath in input.push.affected_files
startswith(normalize_path(filepath), normalize_path(input.stack.project_root))
}
affected if {
some filepath in input.push.affected_files
some glob_pattern in input.stack.additional_project_globs
glob.match(glob_pattern, ["/"], normalize_path(filepath))
}
affected_pr if {
some filepath in input.pull_request.diff
startswith(normalize_path(filepath), normalize_path(input.stack.project_root))
}
affected_pr if {
some filepath in input.pull_request.diff
some glob_pattern in input.stack.additional_project_globs
glob.match(glob_pattern, ["/"], normalize_path(filepath))
}
normalize_path(path) := trim(path, "/")The Rego v0 equivalent is on the default policy docs page. You can use the autoattach label to attach this to every stack.
Confirming the cause
Add sample := true and check the policy samples. They show the real push.affected_files and pull_request.diff per evaluation, which distinguishes an inflated commit range from a project_root or glob mismatch.