From 0a27753354b1df97e4b23dbea1def746a03b3430 Mon Sep 17 00:00:00 2001 From: Juan Sugg Date: Wed, 17 Jun 2026 22:19:44 -0300 Subject: [PATCH 1/3] fix(ci): honor per-caller Docker pull inputs in Linux fresh-host job The Linux fresh-host job read its Docker-pull tuning from the reusable workflow's top-level env, so it ignored the per-caller docker_pull_* inputs that only the macOS job wired through. The Linux prepull therefore ran at a hard-coded parallelism of 4 regardless of the requested 2, and the retry budget could not be tuned per caller. Wire the Linux job to honor the inputs (mirroring macOS) and drop the dead top-level fallbacks so the inputs are the single source of truth. Standardize the retry budget to 5 across callers so the registry backoff stays effective, and correct the input descriptions that wrongly claimed macOS-only scope. Net: parallelism 2 and retry budget 5 on both platforms across all lanes. Add a contract test locking the wiring. --- .github/workflows/fresh-host-acceptance.yml | 12 +++---- .github/workflows/fresh-host-core.yml | 12 ++++--- .github/workflows/nightly.yml | 2 +- .../repo/test_ci_workflow_surfaces.py | 32 +++++++++++++++++++ 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/.github/workflows/fresh-host-acceptance.yml b/.github/workflows/fresh-host-acceptance.yml index cce442b..bb01451 100644 --- a/.github/workflows/fresh-host-acceptance.yml +++ b/.github/workflows/fresh-host-acceptance.yml @@ -4,15 +4,15 @@ on: workflow_call: inputs: docker_pull_parallelism: - description: Parallelism for hosted macOS Docker image pulling. + description: Parallelism for hosted Docker image pulling. required: false type: string default: "2" docker_pull_max_attempts: - description: Retry attempts for hosted macOS Docker image pulling. + description: Retry attempts for hosted Docker image pulling. required: false type: string - default: "3" + default: "5" enable_package_cache: description: Restore uv and npm download caches for bootstrap. required: false @@ -21,15 +21,15 @@ on: workflow_dispatch: inputs: docker_pull_parallelism: - description: Parallelism for hosted macOS Docker image pulling. + description: Parallelism for hosted Docker image pulling. required: true type: string default: "2" docker_pull_max_attempts: - description: Retry attempts for hosted macOS Docker image pulling. + description: Retry attempts for hosted Docker image pulling. required: true type: string - default: "3" + default: "5" enable_package_cache: description: Restore uv and npm download caches for bootstrap. required: true diff --git a/.github/workflows/fresh-host-core.yml b/.github/workflows/fresh-host-core.yml index d3b6fa2..1e20632 100644 --- a/.github/workflows/fresh-host-core.yml +++ b/.github/workflows/fresh-host-core.yml @@ -10,7 +10,9 @@ on: docker_pull_max_attempts: required: false type: string - default: "3" + # 5 attempts give the helper's exponential registry backoff room to ride out a + # transient Docker Hub blip before the prepull gives up. + default: "5" enable_package_cache: required: false type: boolean @@ -21,9 +23,6 @@ permissions: env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" - FRESH_HOST_DOCKER_PULL_PARALLELISM: "4" - # 5 retries let registry backoff survive transient Docker Hub issues - FRESH_HOST_DOCKER_PULL_MAX_ATTEMPTS: "5" FRESH_HOST_CACHE_ROOT: ${{ github.workspace }}/.github-cache UV_CACHE_DIR: ${{ github.workspace }}/.github-cache/uv npm_config_cache: ${{ github.workspace }}/.github-cache/npm @@ -34,6 +33,11 @@ jobs: name: Linux Fresh Host (${{ matrix.profile }}) runs-on: ubuntu-latest timeout-minutes: 75 + # Honor the per-caller pull tuning inputs, mirroring the macOS job. Without this the + # Linux prepull silently ignored docker_pull_* inputs and used hard-coded defaults. + env: + FRESH_HOST_SELECTED_DOCKER_PULL_PARALLELISM: ${{ inputs.docker_pull_parallelism }} + FRESH_HOST_SELECTED_DOCKER_PULL_MAX_ATTEMPTS: ${{ inputs.docker_pull_max_attempts }} strategy: fail-fast: false matrix: diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index acc0c2f..0800fc5 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -61,6 +61,6 @@ jobs: uses: ./.github/workflows/fresh-host-core.yml with: docker_pull_parallelism: "2" - docker_pull_max_attempts: "3" + docker_pull_max_attempts: "5" enable_package_cache: true secrets: inherit diff --git a/tests/suites/contracts/repo/test_ci_workflow_surfaces.py b/tests/suites/contracts/repo/test_ci_workflow_surfaces.py index b862051..c466fae 100644 --- a/tests/suites/contracts/repo/test_ci_workflow_surfaces.py +++ b/tests/suites/contracts/repo/test_ci_workflow_surfaces.py @@ -212,6 +212,38 @@ def test_fresh_host_core_workflow_stays_thin() -> None: assert ".github/scripts/fresh_host_images.py" not in text +def test_fresh_host_core_linux_job_honors_pull_tuning_inputs() -> None: + """The Linux fresh-host job must honor per-caller docker_pull_* inputs, like macOS.""" + loaded_workflow: object = yaml.safe_load(_workflow_text("fresh-host-core.yml")) + assert isinstance(loaded_workflow, dict) + workflow = cast(dict[object, object], loaded_workflow) + + jobs = _as_str_object_dict(workflow.get("jobs")) + assert jobs is not None + + # Both platform jobs must map the selected pull tuning env to the per-caller inputs. + for job_name in ("linux-fresh-host", "macos-fresh-host"): + job = _as_str_object_dict(jobs.get(job_name)) + assert job is not None, job_name + job_env = _as_str_object_dict(job.get("env")) + assert job_env is not None, job_name + assert ( + job_env.get("FRESH_HOST_SELECTED_DOCKER_PULL_PARALLELISM") + == "${{ inputs.docker_pull_parallelism }}" + ), job_name + assert ( + job_env.get("FRESH_HOST_SELECTED_DOCKER_PULL_MAX_ATTEMPTS") + == "${{ inputs.docker_pull_max_attempts }}" + ), job_name + + # The hard-coded top-level fallbacks must stay gone; if they return, the Linux prepull + # would silently override the per-caller inputs again. + workflow_env = _as_str_object_dict(workflow.get("env")) + assert workflow_env is not None + assert "FRESH_HOST_DOCKER_PULL_PARALLELISM" not in workflow_env + assert "FRESH_HOST_DOCKER_PULL_MAX_ATTEMPTS" not in workflow_env + + def test_fresh_host_workflow_preserves_dispatch_inputs_and_concurrency_controls() -> None: """Fresh-host acceptance should keep explicit tuning inputs and concurrency guards.""" text = _workflow_text("fresh-host-acceptance.yml") From 500b6bdef889b84fe9092940bf2738371395d4f6 Mon Sep 17 00:00:00 2001 From: Juan Pedro Sugg Date: Wed, 17 Jun 2026 22:37:07 -0300 Subject: [PATCH 2/3] Update fresh-host-core.yml --- .github/workflows/fresh-host-core.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/fresh-host-core.yml b/.github/workflows/fresh-host-core.yml index 1e20632..7e84397 100644 --- a/.github/workflows/fresh-host-core.yml +++ b/.github/workflows/fresh-host-core.yml @@ -33,8 +33,6 @@ jobs: name: Linux Fresh Host (${{ matrix.profile }}) runs-on: ubuntu-latest timeout-minutes: 75 - # Honor the per-caller pull tuning inputs, mirroring the macOS job. Without this the - # Linux prepull silently ignored docker_pull_* inputs and used hard-coded defaults. env: FRESH_HOST_SELECTED_DOCKER_PULL_PARALLELISM: ${{ inputs.docker_pull_parallelism }} FRESH_HOST_SELECTED_DOCKER_PULL_MAX_ATTEMPTS: ${{ inputs.docker_pull_max_attempts }} From 222257bb45dccf6c69cd6430e438840338bd2aba Mon Sep 17 00:00:00 2001 From: Juan Pedro Sugg Date: Wed, 17 Jun 2026 22:39:27 -0300 Subject: [PATCH 3/3] Update fresh-host-core.yml --- .github/workflows/fresh-host-core.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/fresh-host-core.yml b/.github/workflows/fresh-host-core.yml index 7e84397..6a9b4bf 100644 --- a/.github/workflows/fresh-host-core.yml +++ b/.github/workflows/fresh-host-core.yml @@ -10,8 +10,7 @@ on: docker_pull_max_attempts: required: false type: string - # 5 attempts give the helper's exponential registry backoff room to ride out a - # transient Docker Hub blip before the prepull gives up. + # Give the registry backoff room for transient Docker Hub blips. default: "5" enable_package_cache: required: false