Repository navigation
Conversation
The shard planner weighted projects by Lean file count. Certificate-heavy projects with few files were badly underweighted: in merge-queue run 42209045242 (PR #751, full rebuild) shard 08 held 15 CPU-hours (MovingSofa + ConwaySoifer) and took 4h08m while other shards finished in 1-2h, pushing the run past the queue's 6-hour limit. Weight projects by their measured CPU seconds from a cold build instead, read from scripts/ci/build-costs.json (generated from that run's Lake `Built` lines by the new scripts/ci/measure-build-costs.py). Projects without a measurement are estimated from Lean source size, scaled by the measured projects' seconds per byte. A missing or malformed cost file only warns. Shard count and the single/sharded decision are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Proof profile (new / modified Lean files)No added or modified Lean files under Advisory only — never blocks merge. |
|
Advisory cross-file review against Lean Pool's supervisory rubric. This is not by itself a significance, source-verification, or merge verdict. [Medium impact] The PR appears safe to merge; no actionable new issues were found. SummaryThe PR balances CI shards using measured build times, with source-size estimates for unmeasured projects.
Reviews (2) · Last reviewed commit: "fix: validate shard cost inputs and pres..." · Reviewed by Greptile |
Vilin97
left a comment
There was a problem hiding this comment.
{
"summary": "Technical source review at 61b7df1: measured weights replace file counts only for shard assignment, while the existing skip/single/sharded policy, dirty-project detection, shard-count thresholds and validation gates remain intact. I repaired malformed/nonfinite/negative and overflow handling so bad costs warn and fall back to source bytes, and made zero-cost ties preserve parallelism. Exactly two Python files changed in the repair; 23 focused tests, six end-to-end fallback probes and Ruff checks passed. Two tests requiring the full current project tree were not run locally. The checked-in table contains 329 finite positive weights; the advertised wall-time predictions and private measurement provenance are not independently established. New-head hosted CI and normal protected queue integration remain required; main is still unqualified.",
"assessment": {
"scope": "Cost-based shard scheduling, public log summarizer, measurement table and tests",
"introduces_tech_debt": false,
"maintainability": "improved",
"brittleness": "unchanged",
"risk": "low",
"assessment_one_sentence": "Changes scheduling without removing build targets or checks, with safe malformed-input fallback and deterministic exact-once assignment."
},
"verdict": "approve",
"findings": []
}
Problem
When there's no warm cache (toolchain bumps,
[leanOptions]changes like #751), CI shards the whole pool across 10 runners. The planner weighted each project by Lean file count, which badly underweights certificate-heavy projects with only a few files.In merge-queue run 42209045242 (#751, full rebuild):
Max/mean = 2.27. Shard 08 held MovingSofa (5.8 CPU-h; its
KernelOnly.PartE.Certificates.Bundle*modules take up to 865 s each) plus ConwaySoifer (4.0 CPU-h). Assemble and lint then needed ~2h more, so the run hit the 6h queue limit.Change
scripts/ci/build-costs.json(new): measured CPU seconds per project, the sum of Lake's✔ … Built LeanPool.<P>… (Ns)lines from that run's 10 shard logs (329 projects, 66.0 CPU-h).scripts/ci/measure-build-costs.py(new, stdlib +gh): regenerates that file. Runpython3 scripts/ci/measure-build-costs.py --run <id> > scripts/ci/build-costs.jsonon any full sharded run.scripts/ci/plan-build-shards.py: greedy LPT bin-packing now uses predicted cost:mathlib-bumpcallers. The plan also reportsshard_secondsfor debugging.python/tests/test_build_shard_planner.py(new): log parsing (s/ms units, facet lines, single-file projects), fallback calibration, bad cost files, LPT isolating an expensive few-file project, determinism, an end-to-end cold plan on the real tree (every project exactly once, 10 shards, max ≤ 1.25× mean), and dirty-project sharded vs single.Predicted per-shard load (current tree, cold, measured costs)
*
RareSubtreePatternsmerged after the measured run, so its share is estimated from size.The 3.85 effective cores per runner and ~8 min setup are measured from the same run: each shard's summed
Builtseconds ÷ its build wall-clock was 3.34–3.92. A per-project critical-path check over the import graph shows no project needs longer than ~50 min end to end (HopfProblem 48 min, MovingSofa 47 min). So even the heaviest project parallelizes well within a ~1h50 shard.Expected cold queue run: ~1h51 shards + ~2h assemble ≈ 3h55, against the 6h limit (previously 4h08 + 2h > 6h).
Why this cost source
I compared options using the measured costs as ground truth (LPT, 10 shards, current tree):
/profileis per-PR, and there is no scheduled whole-pool profile.Assemble and lint (~2h): not changed here
From the same run's
finalizejob:Lint(validation_cache lint: onelake env lean --run lint-project.leanper project, sequential)Repository quality checks(declarations/backdoors/axioms per project, sequential)Both are serial loops of single-threaded Lean processes on a 4-core runner. Running them across 3–4 workers would likely cut ~1.5h to ~30 min. That requires editing
python/lean_pool/quality.py/ the workflow's check steps, which CONTRIBUTING reserves for explicitly requested changes, so it's left as a follow-up. This PR alone brings cold runs within the limit.Gates
No gate is weakened. Every project is still built in exactly one shard under the same warning check, and
finalizestill builds the root library and runs every check. No workflow,quality.py, linter orLeanPool/**file is touched.build-costs.jsondoesn't feed the build cache key (ci_cache.build_revisionhashes only.leansources), so editing it never forces a rebuild.Testing
uv run ruff check,uv run ruff format --check: clean.uv run --group test pytest: 865 passed. 4 failures (test_notice::test_repository_notice_is_currentand 3 ×test_proof_profile::test_stitched_logs_cannot_forge_later_file_headers) reproduce identically on unmodifiedmainlocally and are unrelated.🤖 Generated with Claude Code