ci(seed): publish the app-host product from admission's pool, not the stalled 12 vCPU label
Stacked on #27448, which is stacked on #27444. This PR's own commits are 0ebffdf8e78 (test) and 3c27f1a3104 (fix). The four commits before them belong to #27444 and #27448. Merge order: #27444, #27448, this PR.
Summary
seed-derived-data.yml runs on every push to main. Its first seed pool (SEED_POOL_1) is the only pool that publishes the app-host test product. Pull-request compile admission and E2E dispatches adopt that product instead of compiling it (reuse_app_host_products.py, "Reuse exact compatible compiled products"). Under today's 6 vCPU pull-request pool, SEED_POOL_1 resolved to its 12 vCPU sibling, blacksmith-12vcpu-macos-26. That label hasn't started a job since 2026-10-28 20:32Z. In the last 100 nightly.yml runs (back to 2026-10-29 06:18Z), 0 of the 10 jobs that asked for it got a runner. Main's classic nightly run 40834485210 has waited since 07:47Z on it (#27444). Here, every seed (blacksmith-12vcpu-macos-26) job since 2026-10-28 23:28Z was cancelled or is still queued. So main published no app-host product, and every consumer missed it and compiled.
SEED_POOL_1 is now admission's own pool, the same expression as SEED_POOL_2. seed_decide.py drops the duplicate (test_order_is_kept_and_duplicates_dropped), so the pool seeds once and publishes. Today the matrix is [blacksmith-6vcpu-macos-26, blacksmith-6vcpu-macos-15], plus the trusted pool when CI_SEED_TRUSTED_POOL is set.
Consumers of the published product:
ci-macos.ymlcompile admission (pull requests and main's full suite)test-e2e.ymldispatches
Both find the product through reuse_app_host_products.py. It trusts this workflow's seed (<pool>) job by name with any matrix suffix (names_compile_job). Its contract hashes product inputs, Xcode, SDK, arch, tools and the build path, but no runner size ("a 6 and a 12 vCPU runner ... name one product"). A product built on 6 vCPU is therefore adopted the same way, and no consumer needs 12 vCPU.
What a 12 vCPU admission loses: its own j12 DerivedData seed. When the pull-request picker sends admission to 12 vCPU, seed_derived_data.py (nearest_of_any_width) first takes an older j12 seed if one is within 50 commits, and then the j6 seed. Old j12 seeds leave that window in about a day. That costs some re-emitted modules (run 36043267820 measured the reverse direction), but it's better than a seed that never runs. SEEDED_JOB_WIDTHS doesn't change, so existing j12 seeds can still be found.
Other MACOS_RUNNER_PR values behave as before. Unset or macOS 15 gives blacksmith-6vcpu-macos-15. An owned label gives that label. In both cases SEED_POOL_1 already equalled SEED_POOL_2 on base.
Known gaps:
- On the first pushes after this lands, a pool that skips because its inputs are seeded has no product yet. The 6 vCPU seeds never published one. The next push that changes app inputs publishes it.
- The comment at
seed_derived_data.py:106still describes a 12 vCPU seed.
Testing
Regression: python3 tests/test_seed_derived_data.py.
- The new
test_the_product_publisher_seeds_on_a_label_with_capacityevaluates the seed pools for fourMACOS_RUNNER_PRvalues: 6 vCPU macOS 26, macOS 15, an owned label and unset. For each, it checks that no pool is 12 vCPU and that the publisher equals the pool that pull-request admission runs on. - Two existing tests pinned the 12 vCPU publisher:
test_every_pool_admission_compiles_on_gets_a_seed_of_its_width, andtest_the_seed_pool_differs_from_admission_only_in_runner_size, which is nowtest_the_publishing_seed_pool_is_admission_s_own_pool. They now pin admission's pool. - On 0ebffdf8e78 (test only), the three tests fail. On the head, they pass.
Observed / Not run
Observed, run locally on the head, all pass:
test_seed_derived_data.py,test_seed_decide.py,test_reuse_app_host_products.pyandtest_ci_canonical_build_root.py.test_classic_nightly_build_runner.pyandtest_ci_owned_pool_rescue.py.test_ci_pr_runner_pool.pyandtest_ci_queue_janitor.py.test_runner_label_policy.py,test_ci_runs_on_values.pyandtest_ci_no_github_hosted_macos.py.test_ci_pull_request_caches_are_read_only.pyandtest_ci_workflow_concurrency.py.- The signing keychain guard and
test_ci_production_secrets_protected_env.py. test_ci_repo_variable_defaults.py,test_ci_cloud_overflow_switch.pyandtest_ci_change_areas.py.test_ci_e2e_compilation_cache.py,test_e2e_sibling_build.py,test_run_e2e.pyandtest_ci_timing_readout.py.tests/test_ci_test_compilation_cache_seed.sh,tests/test_ci_self_hosted_guard.shandtests/test_nightly_universal_build.sh.- actionlint 1.7.7 (
SHELLCHECK_OPTS=-S warning) onseed-derived-data.yml: clean.
test_ci_owned_pool_sources.py fails 1 check, the same way on origin/main. That check reads the feat-cmux-next tree, so this PR doesn't cause it.
Not run: a seed-derived-data.yml run on main with this change, and a pull request that adopts a product published from 6 vCPU. The product contract was only read, not exercised end to end.
Changelog
none