Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ jobs:
BACKLOG_THRESHOLD: "10"
BACKLOG_THRESHOLD_ARM64: "30"
GH_TOKEN: ${{ github.token }}
# Runners used unless the backlog or a blacksmith-ci label moves a
# run to RUNNER_AMD64/RUNNER_ARM64. Unset, they are GitHub-hosted.
RUNNER_DEFAULT_AMD64_VAR: ${{ vars.RUNNER_DEFAULT_AMD64 }}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
RUNNER_DEFAULT_ARM64_VAR: ${{ vars.RUNNER_DEFAULT_ARM64 }}
RUNNER_AMD64_VAR: ${{ vars.RUNNER_AMD64 }}
RUNNER_ARM64_VAR: ${{ vars.RUNNER_ARM64 }}
# Self-hosted rung for the arm64 pull request container builds. They
Expand All @@ -115,11 +119,11 @@ jobs:
RUNNER_SELFHOSTED_ARM64_VAR: ${{ vars.RUNNER_SELFHOSTED_ARM64 }}
SELFHOSTED_LINT_AUTHORS: ${{ vars.SELFHOSTED_LINT_AUTHORS }}
SELFHOSTED_MAX_QUEUED: "6"
# The amd64 jobs run in two tiers, each GitHub-hosted, then its own
# self-hosted label, then RUNNER_AMD64. Only trusted runs (the
# allowlist above, plus any push to develop or master) leave
# GitHub-hosted. Unset a tier's label to skip its self-hosted step;
# see ci/README.md.
# The amd64 jobs run in two tiers, each on RUNNER_DEFAULT_AMD64, then
# its own self-hosted label, then RUNNER_AMD64. Only trusted runs
# (the allowlist above, plus any push to develop or master) leave
# the default runner. Unset a tier's label to skip its self-hosted
# step; see ci/README.md.
RUNNER_SELFHOSTED_FAST_VAR: ${{ vars.RUNNER_SELFHOSTED_FAST }}
FAST_SELFHOSTED_QUEUE_LIMIT: "16"
RUNNER_SELFHOSTED_BUILD_VAR: ${{ vars.RUNNER_SELFHOSTED_BUILD }}
Expand Down Expand Up @@ -173,7 +177,7 @@ jobs:
runs-on: ${{ needs.check-skip.outputs['runner-fast'] }}

# Pushes build the trusted-* images that later runs reuse, so they stay on
# GitHub's runners; only pull request builds use the fast tier.
# the amd64/arm64 runners; only pull request builds use the fast tier.
container:
permissions:
contents: read
Expand Down Expand Up @@ -629,7 +633,7 @@ jobs:
!cancelled() &&
github.event_name == 'push' &&
github.ref_name == github.event.repository.default_branch
runs-on: ubuntu-24.04-arm
runs-on: ${{ vars.RUNNER_DEFAULT_ARM64 || 'ubuntu-24.04-arm' }}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
permissions:
actions: write
steps:
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/cache-depends-sources.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
description: "Runner label to use"
required: false
type: string
default: ubuntu-24.04-arm
default: ""
schedule:
# Run daily at 6 AM UTC on the default branch to keep cache warm
- cron: '0 6 * * *'
Expand All @@ -18,11 +18,12 @@ permissions:
jobs:
cache-sources:
name: Cache depends sources
# Intentionally keep scheduled cache warming on GitHub-hosted ARM runners.
# Blacksmith caches are expected to persist long enough without a warmup cron.
# Scheduled cache warming runs on RUNNER_CACHE_DEPENDS_SOURCES, by default a
# GitHub-hosted ARM runner. Blacksmith caches are expected to persist long
# enough without a warmup cron.
# build.yml passes its fast tier runner, which may be self-hosted; the cache
# key does not name the runner, so any arch can fill it.
runs-on: ${{ inputs.runs-on || 'ubuntu-24.04-arm' }}
runs-on: ${{ inputs.runs-on || vars.RUNNER_CACHE_DEPENDS_SOURCES || 'ubuntu-24.04-arm' }}
steps:
- name: Checkout code
uses: actions/checkout@v6
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/check-milestone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
main:
name: Require a milestone
if: ${{ github.repository == 'dashpay/dash' && !github.event.pull_request.draft }}
runs-on: ${{ vars.DASH_LIGHT_RUNNER || 'ubuntu-latest' }}
runs-on: ${{ vars.RUNNER_CHECK_MILESTONE || vars.DASH_LIGHT_RUNNER || 'ubuntu-latest' }}
steps:
- name: Check that a milestone is set
env:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/clang-diff-format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ permissions:

jobs:
ClangFormat:
runs-on: ubuntu-latest
runs-on: ${{ vars.RUNNER_CLANG_DIFF_FORMAT || 'ubuntu-latest' }}
steps:
- name: Checkout
uses: actions/checkout@v6
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/guix-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
build-image:
permissions:
packages: write
runs-on: ubuntu-24.04-arm
runs-on: ${{ vars.RUNNER_GUIX_BUILD || 'ubuntu-24.04-arm' }}
if: |
(github.event_name == 'push' && (startsWith(github.ref, 'refs/tags/') || vars.RUN_GUIX_ON_ALL_PUSH == 'true')) ||
contains(github.event.pull_request.labels.*.name, 'guix-build') ||
Expand Down Expand Up @@ -79,7 +79,7 @@ jobs:
build:
needs: build-image
# runs-on: [ "self-hosted", "linux", "x64", "ubuntu-core" ]
runs-on: ubuntu-24.04-arm
runs-on: ${{ vars.RUNNER_GUIX_BUILD || 'ubuntu-24.04-arm' }}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
permissions:
packages: read
id-token: write
Expand Down Expand Up @@ -186,7 +186,7 @@ jobs:
attest:
needs: build
if: github.repository == 'dashpay/dash' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-24.04
runs-on: ${{ vars.RUNNER_GUIX_ATTEST || 'ubuntu-24.04' }}
permissions:
id-token: write
attestations: write
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/label-merge-conflicts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ permissions:

jobs:
main:
runs-on: ${{ vars.DASH_LIGHT_RUNNER || 'ubuntu-latest' }}
runs-on: ${{ vars.RUNNER_LABEL_MERGE_CONFLICTS || vars.DASH_LIGHT_RUNNER || 'ubuntu-latest' }}
steps:
- name: check if prs are dirty
uses: eps1lon/actions-label-merge-conflict@v3.1.0
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/merge-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ on:

jobs:
check_merge:
runs-on: ${{ vars.DASH_LIGHT_RUNNER || 'ubuntu-latest' }}
runs-on: ${{ vars.RUNNER_MERGE_CHECK || vars.DASH_LIGHT_RUNNER || 'ubuntu-latest' }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/predict-conflicts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
predict_conflicts:
# Forks also run scheduled workflows.
if: github.repository == 'dashpay/dash'
runs-on: ${{ vars.DASH_LIGHT_RUNNER || 'ubuntu-latest' }}
runs-on: ${{ vars.RUNNER_PREDICT_CONFLICTS || vars.DASH_LIGHT_RUNNER || 'ubuntu-latest' }}
timeout-minutes: 20
concurrency:
group: predict-conflicts
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/prevent-master-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ permissions: {}

jobs:
fail:
runs-on: ubuntu-latest
runs-on: ${{ vars.RUNNER_PREVENT_MASTER_PR || 'ubuntu-latest' }}
steps:
- run: exit 1

57 changes: 44 additions & 13 deletions .github/workflows/select_dynamic_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
# Prefixes — any label starting with one of these indicates a non-GitHub-hosted runner
NON_GITHUB_HOSTED_RUNNER_PREFIXES = ("blacksmith-",)
SELF_HOSTED_LABEL = "self-hosted"
# GitHub's own runner image labels, such as ubuntu-24.04, ubuntu-24.04-arm,
# ubuntu-latest or windows-11-arm. A bare label like ubuntu-core does not match.
GITHUB_HOSTED_IMAGE_LABEL = re.compile(
r"(ubuntu|windows|macos)-(latest|slim|\d[\d.]*)(-[a-z0-9]+)*", re.IGNORECASE
)
# Any queued GitHub-hosted job at all is enough to prefer our own hardware for
# the arm64 pre-lint jobs.
SELFHOSTED_BACKLOG_THRESHOLD = 0
Expand Down Expand Up @@ -336,28 +341,30 @@ def select_tier_runner(
selfhosted_label: str,
selfhosted_queued: int,
selfhosted_queue_limit: int,
default_runner: str,
blacksmith_runner: str,
label_override: bool,
measurement_error: Optional[str],
disabled_reason: str,
) -> Tuple[str, str]:
"""Pick an amd64 tier's runner: GitHub-hosted, then self-hosted, then Blacksmith.
"""Pick an amd64 tier's runner: default, then self-hosted, then Blacksmith.

Runs that may not use our own hardware stay GitHub-hosted, so Blacksmith
is only ever paid for trusted runs or an explicit blacksmith-ci label.
blacksmith_runner is GitHub-hosted when RUNNER_AMD64 is unset.
default_runner is RUNNER_DEFAULT_AMD64, GitHub-hosted unless set. Runs
that may not use our own hardware stay on it, so Blacksmith is only ever
paid for trusted runs or an explicit blacksmith-ci label.
blacksmith_runner is default_runner when RUNNER_AMD64 is unset.
"""
if label_override:
return blacksmith_runner, "label:blacksmith-ci"

if measurement_error is not None:
return DEFAULT_RUNNER_AMD64, "metric-unavailable"
return default_runner, "metric-unavailable"

if hosted_available:
return DEFAULT_RUNNER_AMD64, hosted_reason
return default_runner, hosted_reason

if not allowed:
return DEFAULT_RUNNER_AMD64, "actor-not-allowed"
return default_runner, "actor-not-allowed"

if not selfhosted_label:
return blacksmith_runner, disabled_reason
Expand Down Expand Up @@ -390,6 +397,8 @@ def select_runners(
runner_selfhosted_build_var: str = "",
build_hosted_queue_limit: int = DEFAULT_BUILD_HOSTED_QUEUE_LIMIT,
build_selfhosted_queue_limit: int = DEFAULT_BUILD_SELFHOSTED_QUEUE_LIMIT,
runner_default_amd64_var: str = "",
runner_default_arm64_var: str = "",
) -> Dict[str, str]:
label_names = [
label.get("name", "")
Expand All @@ -404,6 +413,14 @@ def select_runners(
selfhosted_queued: Dict[str, int] = {}
measurement_error = None

# A default runner set to a label other than one of GitHub's images names
# our own hardware, so its queued jobs must not count towards the backlog.
moved_default_labels = tuple(
label
for label in (runner_default_amd64_var, runner_default_arm64_var)
if label and not GITHUB_HOSTED_IMAGE_LABEL.fullmatch(label)
)
Comment on lines +418 to +422

@thepastaclaw thepastaclaw Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Resolved at 6ee00343; see the replies below.

🔴 Blocking: Keep alternate GitHub-hosted defaults in the backlog count

Changing the default label does not necessarily move jobs off GitHub-hosted capacity. Setting RUNNER_DEFAULT_AMD64 to ubuntu-latest or ubuntu-22.04 adds that hosted label to moved_default_labels, which is passed to targets_github_hosted_runner() as an unconditional non-hosted exclusion. With 40 queued jobs carrying that label and no other hosted jobs queued, backlog_count becomes 0 instead of 40: both amd64 tiers stay on the congested default, and neither architecture crosses its configured backlog-escalation threshold. The exclusion also applies to unrelated jobs using the same label across every scanned repository. The documented intent to exclude custom hardware is valid, but label inequality does not establish hosting type. Preserve alternate GitHub-hosted labels in the classification logic while retaining the custom-runner exclusion, and extend the existing backlog scenario to cover both cases.

source: gpt-6.1-sol (phase2-reviewer: general)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, fixed in 6ee0034. Changing the default no longer counts as moving it off GitHub-hosted on its own. A default is excluded from the backlog only when it isn't one of GitHub's image labels (GITHUB_HOSTED_IMAGE_LABEL, which matches labels such as ubuntu-24.04, ubuntu-22.04-arm, ubuntu-latest, windows-11-arm and macos-15-intel). So ubuntu-22.04 and ubuntu-latest stay in the count, and a bare label like own-amd64 or ubuntu-core is still excluded.

The backlog scenario now also covers a moved arm64 default (31 queued, backlog 0) and an alternate GitHub image default (ubuntu-22.04, 11 queued, still counted, escalates). The README sentence matches. Both new cases fail without the change.


🤖 Posted autonomously by Claude on behalf of pasta.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved (re-reviewed at 6ee00343): Verified your fix in 6ee0034: only defaults that fail GITHUB_HOSTED_IMAGE_LABEL.fullmatch enter the non-hosted exclusions, so ubuntu-22.04 and ubuntu-latest remain counted while custom defaults are excluded. The regression assertions cover custom defaults on both architectures and counting plus escalation for ubuntu-22.04, and the README matches the corrected rule.


try:
backlog_count_value, selfhosted_queued = count_queued_jobs(
fetch_json,
Expand All @@ -412,7 +429,7 @@ def select_runners(
runner_selfhosted_arm64_var,
runner_selfhosted_fast_var,
runner_selfhosted_build_var,
),
) + moved_default_labels,
)
backlog_count = str(backlog_count_value)
except Exception as exc: # noqa: BLE001
Expand Down Expand Up @@ -447,21 +464,22 @@ def select_runners(
measurement_error is None and backlog_count_value > arm64_threshold
)

runner_amd64 = DEFAULT_RUNNER_AMD64
runner_arm64 = DEFAULT_RUNNER_ARM64
default_amd64 = runner_default_amd64_var or DEFAULT_RUNNER_AMD64
runner_amd64 = default_amd64
runner_arm64 = runner_default_arm64_var or DEFAULT_RUNNER_ARM64
fallback_parts: List[str] = []

if use_blacksmith_amd64:
if runner_amd64_var:
runner_amd64 = runner_amd64_var
else:
fallback_parts.append("amd64-github-fallback")
fallback_parts.append("amd64-default-fallback")

if use_blacksmith_arm64:
if runner_arm64_var:
runner_arm64 = runner_arm64_var
else:
fallback_parts.append("arm64-github-fallback")
fallback_parts.append("arm64-default-fallback")

if measurement_error is not None:
decision_parts.append("error:{}".format(measurement_error[:180]))
Expand Down Expand Up @@ -499,7 +517,7 @@ def selfhosted(
)

trusted = is_amd64_selfhosted_allowed(event_name, event, actor, allowed_authors)
blacksmith_amd64 = runner_amd64_var or DEFAULT_RUNNER_AMD64
blacksmith_amd64 = runner_amd64_var or default_amd64

def tier(
hosted_available: bool,
Expand All @@ -515,6 +533,7 @@ def tier(
selfhosted_label=selfhosted_label,
selfhosted_queued=selfhosted_queued.get(selfhosted_label.lower(), 0),
selfhosted_queue_limit=queue_limit,
default_runner=default_amd64,
blacksmith_runner=blacksmith_amd64,
label_override=label_override,
measurement_error=measurement_error,
Expand Down Expand Up @@ -646,6 +665,16 @@ def parse_args(argv: Sequence[str]) -> argparse.Namespace:
default=env_int("BACKLOG_THRESHOLD_ARM64", default_backlog_threshold * 3),
help="Queued job threshold for switching arm64 jobs to Blacksmith",
)
parser.add_argument(
"--runner-default-amd64-var",
default=os.environ.get("RUNNER_DEFAULT_AMD64_VAR", ""),
help="amd64 runner label used without escalation; empty means {}".format(DEFAULT_RUNNER_AMD64),
)
parser.add_argument(
"--runner-default-arm64-var",
default=os.environ.get("RUNNER_DEFAULT_ARM64_VAR", ""),
help="arm64 runner label used without escalation; empty means {}".format(DEFAULT_RUNNER_ARM64),
)
parser.add_argument(
"--runner-amd64-var",
default=os.environ.get("RUNNER_AMD64_VAR", ""),
Expand Down Expand Up @@ -756,6 +785,8 @@ def main(argv: Sequence[str]) -> int:
runner_selfhosted_build_var=args.runner_selfhosted_build_var,
build_hosted_queue_limit=args.build_hosted_queue_limit,
build_selfhosted_queue_limit=args.build_selfhosted_queue_limit,
runner_default_amd64_var=args.runner_default_amd64_var,
runner_default_arm64_var=args.runner_default_arm64_var,
)

write_github_output(os.environ.get("GITHUB_OUTPUT"), outputs)
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/semantic-pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ permissions:
jobs:
main:
name: Validate PR title
runs-on: ${{ vars.DASH_LIGHT_RUNNER || 'ubuntu-latest' }}
runs-on: ${{ vars.RUNNER_SEMANTIC_PULL_REQUEST || vars.DASH_LIGHT_RUNNER || 'ubuntu-latest' }}
steps:
- uses: amannn/action-semantic-pull-request@v6
env:
Expand Down
Loading
Loading