Skip to content

Commit 940063d

Browse files
committed
Merge branch 'master' into continuousLinearEquiv_ofContinuousLinear
2 parents 8c7222b + 32e89fb commit 940063d

3,952 files changed

Lines changed: 30265 additions & 16717 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.git-blame-ignore-revs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@
44
fc48848e4374f13c796a7399bfccd2e228f776df
55
# 2025-11-19 move Mathlib to the module system (#31786)
66
6a54a80825b060ab20dc31751ebdce78b3a3b518
7+
# 2025-12-01 fix spelling in doc-strings (#32286)
8+
b728e1450a53133aa4171eeadc0bc8d3ee58415c

.github/actions/cache-trust-dispatch/action.yml

Lines changed: 58 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Single source of truth mapping (repo, branch) → (upload container,
1+
# Single source of truth mapping (repo, ref) → (upload container,
22
# read fallback chain) for Mathlib's multi-container cache.
33
#
44
# Called by build, upload_cache, and post_steps in build_template.yml so
@@ -14,7 +14,10 @@ inputs:
1414
description: GitHub repo full name (`owner/name`).
1515
required: true
1616
branch:
17-
description: Branch name (`github.head_ref || github.ref_name`).
17+
description: |
18+
Branch name (`github.head_ref || github.ref_name`); on tag-triggered
19+
runs this is the tag name, distinguished via `github.ref_type` inside
20+
the dispatch step.
1821
required: true
1922
head-sha:
2023
description: |
@@ -55,6 +58,10 @@ runs:
5558
REPO="${{ inputs.repo }}"
5659
BRANCH="${{ inputs.branch }}"
5760
HEAD_SHA="${{ inputs.head-sha }}"
61+
# Whether `branch` names a branch or a tag. Read from the run context
62+
# rather than an input: unlike `repo`/`branch`, the value does not
63+
# depend on which event shape (PR vs push) the caller handles.
64+
REF_TYPE="${{ github.ref_type }}"
5865
PRIMARY=""
5966
READ_CHAIN=""
6067
REPO_SCOPE=""
@@ -80,30 +87,55 @@ runs:
8087
else
8188
case "$REPO" in
8289
"leanprover-community/mathlib4")
83-
case "$BRANCH" in
84-
"master"|"staging")
85-
# Master / staging are the only writers that feed `master`
86-
# (`staging` is bors's merge candidate, which fast-forwards to
87-
# `master`). Read `master` only, not the default [master,
88-
# legacy]: files the read chain serves are skipped at stage
89-
# time, so keeping `legacy` would leave legacy-only files out of
90-
# `master` for good. Reading `master` alone turns them into
91-
# misses that get rebuilt and uploaded, so `master` fills itself
92-
# into a standalone cache. (Only PRIMARY=master does this; other
93-
# runs write to `forks` and keep the wider chain.)
94-
PRIMARY="master"
95-
READ_CHAIN="master"
96-
;;
97-
*)
98-
# `bors trying`, `ci-dev/*`, maintainer dev branches on the
99-
# canonical repo: trust level is fork-equivalent (the OIDC
100-
# token's RBAC scopes them to `forks`). Reads must widen
101-
# past the default [master, legacy] so the post-build
102-
# verification finds the just-uploaded fork-trust artifacts.
103-
PRIMARY="forks"
104-
READ_CHAIN="master,forks,legacy"
105-
;;
106-
esac
90+
if [ "$REF_TYPE" = "tag" ]; then
91+
case "$BRANCH" in
92+
v4.*)
93+
# `v4.*` release tags: release_cache.yml rebuilds off-master
94+
# release commits (patch releases, patched release
95+
# candidates) and publishes them into `master`, the container
96+
# canonical checkouts read. Tag creation is restricted to
97+
# release managers by a tag ruleset, and the
98+
# `cache-upload-master` environment admits `v4.*` tag refs,
99+
# so these builds carry master trust. Reads are `master`-only
100+
# for the same fill-in reason as the master/staging arm
101+
# below.
102+
PRIMARY="master"
103+
READ_CHAIN="master"
104+
;;
105+
*)
106+
# Other tags have no trust class of their own:
107+
# fork-equivalent, like the dev-branch arm below.
108+
PRIMARY="forks"
109+
READ_CHAIN="master,forks,legacy"
110+
;;
111+
esac
112+
else
113+
case "$BRANCH" in
114+
"master"|"staging")
115+
# Master, staging, and `v4.*` release tags (above) are the
116+
# only writers that feed `master` (`staging` is bors's merge
117+
# candidate, which fast-forwards to `master`). Read `master`
118+
# only, not the default [master, legacy]: files the read
119+
# chain serves are skipped at stage time, so keeping `legacy`
120+
# would leave legacy-only files out of `master` for good.
121+
# Reading `master` alone turns them into misses that get
122+
# rebuilt and uploaded, so `master` fills itself into a
123+
# standalone cache. (Only PRIMARY=master does this; other
124+
# runs write to `forks` and keep the wider chain.)
125+
PRIMARY="master"
126+
READ_CHAIN="master"
127+
;;
128+
*)
129+
# `bors trying`, `ci-dev/*`, maintainer dev branches on the
130+
# canonical repo: trust level is fork-equivalent (the OIDC
131+
# token's RBAC scopes them to `forks`). Reads must widen
132+
# past the default [master, legacy] so the post-build
133+
# verification finds the just-uploaded fork-trust artifacts.
134+
PRIMARY="forks"
135+
READ_CHAIN="master,forks,legacy"
136+
;;
137+
esac
138+
fi
107139
;;
108140
"leanprover-community/mathlib4-nightly-testing")
109141
case "$BRANCH" in

.github/actions/get-mathlib-ci/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ inputs:
1010
# Default pinned commit used by workflows unless they explicitly override.
1111
# Update this ref as needed to pick up changes to mathlib-ci scripts
1212
# This is also updated automatically by .github/workflows/update_dependencies.yml
13-
default: 0cd6cbc879d9241f3b4f6cb7e8291e34128c5654
13+
default: 5668fbbccf0fecefdfcddf539b8406db197dfc59
1414
path:
1515
description: Checkout destination path.
1616
required: false

.github/workflows/add_label_from_diff.yaml

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@ name: Autolabel PRs
33
on:
44
pull_request_target:
55
types: [opened]
6-
push:
7-
paths:
8-
- scripts/autolabel.lean
9-
- .github/workflows/add_label_from_diff.yaml
106

117
# Limit permissions for GITHUB_TOKEN for the entire workflow
128
permissions:
@@ -51,31 +47,7 @@ jobs:
5147
- name: Run autolabel
5248
working-directory: pr-branch
5349
run: |
54-
labels="$("${GITHUB_WORKSPACE}/tools/.lake/build/bin/autolabel")"
55-
printf '%s\n' "${labels}"
56-
# extract
57-
label="$(printf '%s' "${labels}" | sed -n 's=^::notice::.*#\[\([^,]*\)\].*=\1=p')"
58-
printf 'label: "%s"\n' "${label}"
59-
if [ -n "${label}" ] && [ -n "${PR_NUMBER}" ]
60-
then
61-
printf 'Applying label %s\n' "${label}"
62-
# we use curl rather than octokit/request-action so that the job won't fail
63-
# (and send an annoying email) if the labels don't exist
64-
url="https://api.github.com/repos/${{ github.repository }}/issues/${PR_NUMBER}/labels"
65-
printf 'url: %s\n' "${url}"
66-
jsonLabel="$(printf '{"labels":["%s"]}' "${label}")"
67-
printf 'jsonLabel: %s\n' "${jsonLabel}"
68-
curl --request POST \
69-
--header 'Accept: application/vnd.github+json' \
70-
--header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' \
71-
--header 'X-GitHub-Api-Version: 2022-11-28' \
72-
--url "${url}" \
73-
--data "${jsonLabel}"
74-
else
75-
echo "There is no single label that we could apply, so we are not applying any label."
76-
fi
50+
"${GITHUB_WORKSPACE}/tools/.lake/build/bin/autolabel" --pr "${{ github.event.pull_request.number }}" --curl "${{ secrets.GITHUB_TOKEN }}"
7751
env:
7852
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
79-
# the PR number could be undefined in workflows triggered by 'push',
80-
# in which case we only log the applicable label and exit
8153
PR_NUMBER: ${{ github.event.pull_request.number }}

.github/workflows/build_template.yml

Lines changed: 63 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
# Reusable workflow invoked by build.yml, bors.yml, build_fork.yml, and ci_dev.yml.
1+
# Reusable workflow invoked by build.yml, bors.yml, build_fork.yml, ci_dev.yml,
2+
# and release_cache.yml.
23

34
on:
45
workflow_call:
@@ -686,12 +687,18 @@ jobs:
686687
# Sparse-checkout master's `.github/actions/` so the trust dispatch
687688
# below loads from a trust-rooted source, not from PR-branch-controlled
688689
# content. Mirrors the `Checkout local actions` step in the `build` job.
689-
- name: Checkout local actions
690+
# Also check out the cache tool (`Cache/`) at this ref. The verify step
691+
# below compares it against the PR branch's `Cache/` to classify a cache
692+
# miss. `github.workflow_sha` is the base ref the workflow runs from,
693+
# master for fork PRs, whose `cache` binary wrote the cache.
694+
- name: Checkout local actions and Cache baseline
690695
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
691696
with:
692697
ref: ${{ github.workflow_sha }}
693698
fetch-depth: 1
694-
sparse-checkout: .github/actions
699+
sparse-checkout: |
700+
.github/actions
701+
Cache
695702
path: workflow-actions
696703

697704
# Sets MATHLIB_CACHE_FROM in env so the `cache get` calls below pick
@@ -730,16 +737,60 @@ jobs:
730737
lake exe cache --repo=${{ github.event.pull_request.head.repo.full_name || github.repository }} get Archive Counterexamples
731738
732739
- name: verify that everything was available in the cache
740+
# Verify the cache reconstitutes this commit's oleans. This job reads
741+
# the cache with the PR branch's own `lake exe cache get`. The write
742+
# path uses master's `cache` binary for fork PRs and the PR branch's
743+
# binary for every other build. So a fork PR whose `Cache/` differs
744+
# from master reads a different `.ltar` key space (say, after a
745+
# `rootHashGeneration` bump) and misses every file. That is an expected
746+
# invalidation: warn and continue. Any other build reads and writes
747+
# with the same binary, so a miss there is a real gap and is fatal.
748+
env:
749+
# GitHub sets this from the event payload; it is empty for pushes
750+
# (master, bors), so those fail closed below.
751+
HEAD_REPO_IS_FORK: ${{ github.event.pull_request.head.repo.fork }}
733752
run: |
734-
echo "::group::{verify Mathlib cache}"
735-
lake build --no-build --rehash -v Mathlib
736-
echo "::endgroup::"
737-
echo "::group::{verify Archive cache}"
738-
lake build --no-build --rehash -v Archive
739-
echo "::endgroup::"
740-
echo "::group::{verify Counterexamples cache}"
741-
lake build --no-build --rehash -v Counterexamples
742-
echo "::endgroup::"
753+
set +e
754+
fail=0
755+
for target in Mathlib Archive Counterexamples; do
756+
echo "::group::{verify ${target} cache}"
757+
lake build --no-build --rehash -v "${target}" || fail=1
758+
echo "::endgroup::"
759+
done
760+
if [ "${fail}" -eq 0 ]; then
761+
exit 0
762+
fi
763+
764+
# Only fork PRs read and write the cache with different binaries.
765+
# Every other build (master, bors, dev branches) uses one binary, so
766+
# a miss is a real gap.
767+
if [ "${HEAD_REPO_IS_FORK}" != "true" ]; then
768+
echo "::error::Cache verification failed on an in-repo build; the uploaded cache is incomplete."
769+
exit 1
770+
fi
771+
772+
# `workflow-actions/Cache` is master's cache tool at
773+
# `github.workflow_sha`; `Cache` is the PR branch's. Matching source
774+
# means the key spaces agree, so the miss is a real gap. Differing
775+
# source means the PR changed the key space, so the miss is expected.
776+
# The cache writer is master's binary at upload time, which can be
777+
# newer than `workflow_sha` when a `Cache/` change lands on master
778+
# mid-build; that skew can only hard-fail like an unguarded verify
779+
# or soft-pass a key space that genuinely diverged.
780+
dout=$(diff -rq workflow-actions/Cache Cache 2>&1)
781+
dstat=$?
782+
if [ "${dstat}" -eq 0 ]; then
783+
echo "::error::Cache verification failed and this PR's Cache/ matches master's, so the key spaces agree: the uploaded cache is incomplete."
784+
exit 1
785+
elif [ "${dstat}" -eq 1 ]; then
786+
echo "::warning::Cache verification incomplete, but this PR's Cache/ differs from master's. CI wrote the cache with master's binary and this job reads it with the PR branch's, so a changed key space (such as a rootHashGeneration bump) misses as expected. Continuing; the cache repopulates once this lands on master."
787+
echo "${dout}"
788+
exit 0
789+
else
790+
echo "::error::Cache verification failed and master's Cache/ baseline could not be compared (diff status ${dstat}); treating as a failure."
791+
echo "${dout}"
792+
exit 1
793+
fi
743794
744795
- name: check declarations in db files
745796
run: |
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
name: publish release cache
2+
3+
# Publishes the Mathlib cache for release tags whose commits are not on
4+
# `master`.
5+
#
6+
# Patch releases (`v4.X.Y` with Y ≥ 1) and patched release candidates (e.g.
7+
# `v4.32.0-rc1-patch1`) are committed on `bump_to_*` branches that never merge
8+
# back into `master`, so the master push build never caches them; their branch
9+
# CI writes only the fork-trust container, which a canonical checkout at the
10+
# tag never reads. This workflow rebuilds the tagged commit and publishes the
11+
# result to the `master` container, where every consumer finds it. Tags that
12+
# point at commits on `master` (plain release candidates and `.0` releases)
13+
# are already cached by the master push build, so the gate job skips them.
14+
#
15+
# Trust model:
16+
# - Creating a `v4.*` tag is restricted to release managers by a tag
17+
# ruleset, so a tag push is a deliberate release-manager action — and the
18+
# tagged tree is what runs here, including this workflow file. Tags cut
19+
# from lineages predating this file simply never trigger it.
20+
# - The upload job mints its OIDC token under the `cache-upload-master`
21+
# environment (inside build_template.yml); the environment's deployment
22+
# policy admits only `master`, `staging`, and `v4.*` tag refs.
23+
#
24+
# Retry: a spuriously failed run can simply be re-run ("Re-run failed jobs" /
25+
# `gh run rerun`) — same tag, same tree, no tag re-push involved. The
26+
# `workflow_dispatch` trigger covers what re-run cannot: a tag push that never
27+
# produced a run, or a re-run window that has expired. Dispatch it AT the tag
28+
# ref (`gh workflow run release_cache.yml --ref v4.X.Y`); the run then executes
29+
# the tag's own tree exactly as a tag push would.
30+
31+
on:
32+
push:
33+
tags:
34+
- 'v4.*'
35+
# Manual fallback; see the retry note above. The `tags` filter does not
36+
# apply to dispatches — the gate job's ref guards enforce it instead, so a
37+
# dispatch on a branch ref skips cleanly.
38+
workflow_dispatch:
39+
40+
# `v4.*` tags are immutable (the tag ruleset blocks updates), so this group
41+
# only ever collides on re-runs of the same tag; keep those queued rather
42+
# than cancelled.
43+
concurrency:
44+
group: ${{ github.workflow }}-${{ github.ref }}
45+
46+
# Read-only by default; the build job elevates for itself only.
47+
permissions:
48+
contents: read
49+
50+
jobs:
51+
gate:
52+
name: skip tags already on master
53+
# The ref guards double as the dispatch-path filter; on the push path the
54+
# `tags` trigger filter has already enforced them.
55+
if: ${{ github.repository == 'leanprover-community/mathlib4' && github.ref_type == 'tag' && startsWith(github.ref_name, 'v4.') }}
56+
runs-on: ubuntu-latest
57+
outputs:
58+
off_master: ${{ steps.check.outputs.off_master }}
59+
steps:
60+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
61+
with:
62+
# `merge-base` needs history, so fetch all of it.
63+
fetch-depth: 0
64+
65+
- name: check whether the tagged commit is on master
66+
id: check
67+
run: |
68+
if git merge-base --is-ancestor "$GITHUB_SHA" origin/master; then
69+
echo "Tag $GITHUB_REF_NAME points at a commit on master; the master push build covers its cache."
70+
echo "off_master=false" >> "$GITHUB_OUTPUT"
71+
else
72+
echo "Tag $GITHUB_REF_NAME is not on master; rebuilding it to publish its cache."
73+
echo "off_master=true" >> "$GITHUB_OUTPUT"
74+
fi
75+
76+
build:
77+
name: ci
78+
needs: gate
79+
if: ${{ needs.gate.outputs.off_master == 'true' }}
80+
# What build_template.yml needs, granted to this job only — the same set
81+
# build.yml grants it on push events. In particular, the OIDC token for
82+
# the cache upload can be minted here and nowhere else in this workflow.
83+
permissions:
84+
contents: read
85+
id-token: write
86+
actions: read # Allow get-tools to download the prebuilt tools artifact from master's publish_tools runs
87+
pull-requests: write # Only allow PR comments/labels
88+
uses: ./.github/workflows/build_template.yml
89+
with:
90+
concurrency_group: ${{ github.workflow }}-${{ github.ref }}
91+
pr_branch_ref: ${{ github.sha }}
92+
# Release tags publish to the `master` container under the master writer
93+
# identity; see the trust note above and cache-trust-dispatch, which
94+
# routes `v4.*` tag refs to that container.
95+
cache_application_id: ${{ vars.CACHE_MASTER_WRITER_AZURE_APP_ID }}
96+
cache_environment: cache-upload-master
97+
# The cache-snapshot warming artifact exists to seed master and PR
98+
# builds, which a release tag's snapshot cannot do.
99+
publish_cache: false
100+
# Skip the Post-CI job: it grooms PR labels, and a tag run has no PR.
101+
run_post_ci: false
102+
runs_on: pr
103+
secrets: inherit

0 commit comments

Comments
 (0)