Skip to content

fix: resolve the openkal index and runtime revisions once per run - #804

Merged
Sunrisepeak merged 3 commits into
mcpp-community:mainfrom
ZheFeng7110:fix/ci-openkal-pinned-revisions
Oct 15, 2026
Merged

Sunrisepeak merged 3 commits into
mcpp-community:mainfrom
ZheFeng7110:fix/ci-openkal-pinned-revisions

Conversation

@ZheFeng7110

Copy link
Copy Markdown
Member

Summary

openkal-cross.yml has four build jobs that each cloned main of
mcpp-community/mcpp-index and of mcpplibs/openkal-llvm-runtime of their own
accord, and three run jobs that then assert all four hosts built the same
sources. Four clones of a moving branch are not four copies of one revision.

That is what failed in run 38399400601
(PR #803, 2026-10-13): all three run jobs reported

::error::index sources differ

The run started at 12:43 UTC and its build jobs at 12:52:08, 12:53:44,
12:58:20 and 13:01:33 UTC, and they do not clone at the same point in their own
step sequence (the macOS leg builds its own mcpp first), while
mcpp-index@main took four commits inside that window — 21b9a77a 12:56:12,
d3a328c8 13:04:42, cfb808bc 13:10:06, 0340de61 13:17:58. Two clones
straddling one push is all it takes, and the reading arrives 40 minutes later
in a job that built nothing. Nothing about the change under test was involved,
and a rerun only re-rolls the dice.

The fix

  • A new revisions job runs first and resolves mcpp-index@main and
    openkal-llvm-runtime@$OPENKAL_BRANCH to one commit each.
  • The four build jobs materialise those commits instead of cloning a branch.
    The run jobs keep their cross-host comparison: it is now what proves a host
    used the pin rather than re-resolving for itself.
  • OPENKAL_BRANCH keeps its meaning — an override still verifies exactly what
    it named, resolved once instead of once per runner.

git_clone_retry.sh grows the two primitives that needs, under the retry the
helper already exists for (a resolver blip is not a red build):

  • --rev <ref> <url> — print the commit a ref names, without downloading the
    tree (ls-remote; both repositories are ~17 MB).
  • --commit <sha> <url> <dir> — materialise exactly that commit
    (init + fetch --depth 1 origin <sha>, since --branch takes a branch or
    a tag and a commit is neither).

Pinning a SHA into the workflow was the alternative and it is the wrong one:
it is the pin-nobody-is-reminded-to-move that the file's own OPENKAL_BRANCH
comment is annotated with.

Verification

  • git_clone_retry.sh: 16 cases against throwaway local repositories —
    --rev for a branch name, a full ref and HEAD; a ref that does not exist
    (exit 1, no retry); an unreachable URL (retries, then gives up); --commit
    for an older commit (detached, no stray branch ref), the tip, a 0…0 SHA and
    a non-SHA; a non-empty destination (self-heals); the plain-clone path and its
    partial-clone removal. All pass; bash -n clean.
  • Against GitHub itself: --rev main on mcpp-index resolved to
    0340de61ffc83f0eeeae459e74a4156b11935897, and --commit materialised
    exactly that commit (813 files, detached HEAD) — the fetch-by-SHA the pin
    depends on works on the host the jobs run against.
  • The revisions step's shell was executed with a stub helper: it emits
    index=/runtime= to $GITHUB_OUTPUT, calls the helper with the two refs,
    and fails with ::error::not a commit on a non-commit.
  • tests/e2e/232_workflow_syntax.sh passes (24 workflows load);
    .github/tools/check_workflow_assertions.py reports 0 problems;
    tools/lint-ci-assertions.sh reports the same two pre-existing warnings as
    before this change; git diff --check clean.

.github/** classifies as code=true, so this PR's own CI runs the full
matrix — including the four-host openkal build and the three run jobs the
pin is for.

Test plan

  • Documentation-only: not applicable, no documentation changed
  • mcpp test (unit/integration): not applicable, no C++ changed
  • The openkal jobs in this PR's CI are the E2E coverage of the change

@ZheFeng7110
ZheFeng7110 force-pushed the fix/ci-openkal-pinned-revisions branch from aff91b0 to 608d307 Compare October 13, 2026 13:40
@ZheFeng7110

Copy link
Copy Markdown
Member Author

CI analysis: the two red checks are flaky, and neither one is this diff

Run 38406939721 (this PR's head 608d3072) ended 60/62 green. Both failures are pre-existing flakes outside the two files this PR touches, and the openkal jobs the change exists for are all green — the four build jobs, the three run jobs and the new revisions job.

1. windows / bare Windows: no Visual Studio (windows x64), 17s — the mask's rename was refused

masking C:\Program Files\Microsoft Visual Studio\18\Enterprise\VC
  rename failed: Access to the path '...\18\Enterprise\VC' is denied.
FAIL: VC tools still present after masking:
  C:\Program Files\Microsoft Visual Studio\18\Enterprise\VC\Tools\MSVC
##[error]Process completed with exit code 1.

The step relies on "the Visual Studio root is held open on the runner and renaming it is denied, while VC one level down renames fine" (ci-windows.yml). That premise is host state, not image state — the same script on the same image:

time (UTC) runner image renaming ...\18\Enterprise\VC
09:57 windows-2025-vs2026, commit 20260925.250 ok
13:59 (this run) same denied
14:32 same ok

ci-windows.yml is not in this diff, and the same step on the same image passed 33 minutes later (run 38411372563). The mask's own postcondition is deliberate — an incomplete mask must not read as a green "bare Windows" row — so a transient denial becomes a red check.

2. macos-e2e / e2e suite 2/2 (xcode-27) — 845 kills mcpp before the phase its assertion names

E2E Summary: 144 passed, 1 failed, 170 skipped, Failed: 845_play_game_restores_the_terminal.sh, from the script's own play.py:71:

AssertionError: G1: no status row carries the score
assert re.search(r"Building .* · snake \d+", plain), ...

The captured g3.log stops in the Programs phase:

Running ⠀⠐⠒⠂… 0/1 · 0:01 · build.mcpp app compiling 0:01 · snake 0
build.mcpp app               ran 1.24s
Running ⠀⠀⠒⠒… 1/1 · 0:01 · snake 0

play.py sends the arrows and the Ctrl-C at a fixed t0 + 1.5s, while the build reaches Phase::Building only after the Programs phase (build.mcpp compile + run, plus toolchain resolution), which took ~1.24s here. The rows do carry the score in the Programs frames; phase_status() prints Running for Phase::Programs and Building only for Phase::Building (src/build/progress.cppm:1074), so the only missing token is the phase word. A 1.5s deadline against ~1.24s of work is decided by host jitter:

  • the macos-15 twin of this job passed in this same run;
  • on main (38378041638) the macos-15 twin failed with the identical assertion while xcode-27 passed;
  • 2 of the last 11 ci runs failed e2e suite 2/2, the two hosts alternating.

Next

Both are fixed in a follow-up PR: e2e 845 waits for the frame its assertion names instead of for a wall-clock delay, and the Visual Studio mask — currently three copies of the same block, in ci-windows.yml, ci-fresh-install.yml and measure-windows-tool-crt.yml — gains retries with a one-level-deeper fallback, with the postcondition kept.

@ZheFeng7110

Copy link
Copy Markdown
Member Author

Both are fixed in #806: e2e 845 now waits for the status row its assertion names instead of for a wall-clock delay, and the Visual Studio mask (three copies, now one action) retries a refused rename and falls back to masking VC\Tools, postcondition kept.

@ZheFeng7110

Copy link
Copy Markdown
Member Author

@Sunrisepeak 我把 #806 的修改 cherry pick 过来后, CI 现已通过

@Sunrisepeak

Copy link
Copy Markdown
Member
  1. rebase 到 main:cherry-pick 进来的 fix: two flaky required checks — the Visual Studio mask and e2e 845 #806 已经以 b5630e2 合进 main 了,把这个重复的 commit 去掉
  2. ecosystem-native-arm64 也用同一个版本:这个 job 现在还是自己 checkout mcpp-index@main,加上 needs: revisions,并把 ref: 设成 ${{ needs.revisions.outputs.index }},这样整次运行用的都是同一个 index 版本。

@ZheFeng7110
ZheFeng7110 force-pushed the fix/ci-openkal-pinned-revisions branch from 5ff0678 to 7102abb Compare October 15, 2026 06:47
The four build jobs of openkal-cross.yml each cloned `main` of the index and
of the runtime of their own accord, at four different moments on four runners
that become available at four different times, and the run jobs then asserted
that all four had built the same sources. On 2026-10-13 that assertion failed
for a reason the change under test had nothing to do with: run 38399400601
started at 12:43 UTC, its build jobs at 12:52:08 through 13:01:33, and
mcpp-index@main took four commits inside that window (21b9a77a 12:56:12,
d3a328c8 13:04:42, cfb808bc 13:10:06, 0340de61 13:17:58), so the four clones
straddled pushes and the run jobs reported `index sources differ`.

Resolve both refs once, in a new `revisions` job, and have every host
materialise the commit it names. OPENKAL_BRANCH keeps its meaning: an
override still verifies exactly what it named, now as one commit rather than
as whatever the branch had become when each runner woke up. The run jobs keep
their cross-host comparison; it is what proves a host used the pin rather
than re-resolving for itself.

git_clone_retry.sh grows the two primitives that needs: `--rev <ref> <url>`,
which prints the commit a ref names without downloading the tree, and
`--commit <sha> <url> <dir>`, which materialises exactly that commit, both
under the retry the helper already exists for. Writing a SHA into the
workflow instead would be the pin-that-keeps-a-check-green-by-keeping-it-
out-of-date that the file itself warns about.
@ZheFeng7110
ZheFeng7110 force-pushed the fix/ci-openkal-pinned-revisions branch from 7102abb to 6ff9cca Compare October 15, 2026 06:54
The job died on 2026-10-15 (run 38695300904) in apt's unpack of wine's
i386 closure, before a single byte was compiled:

    dpkg: error processing archive
     .../libxml2_2.9.14+dfsg-1.3ubuntu3.10_i386.deb (--unpack):
     trying to overwrite shared
     '/usr/share/doc/libxml2/changelog.Debian.gz', which is different
     from other instances of package libxml2:i386

libpng16-16t64, libx11-6 and libfreetype6, all alike. Multi-Arch: same
instances must share every file bit-for-bit, and the i386 and amd64 debs
in the Ubuntu archive embed changelogs that differ (Launchpad #1574351
and its kin). That is a property of the archive, not of the runner: the
step's own `|| sudo apt-get install -y wine` retry failed with the
identical error, so a rerun re-rolls nothing.

Give dpkg --force-overwrite on every install this step makes, the cold
path and the cached-debs path alike. The changelogs are not what this
job reads; wine is.
@ZheFeng7110

Copy link
Copy Markdown
Member Author
  1. rebase 到 main:cherry-pick 进来的 fix: two flaky required checks — the Visual Studio mask and e2e 845 #806 已经以 b5630e2 合进 main 了,把这个重复的 commit 去掉

    1. ecosystem-native-arm64 也用同一个版本:这个 job 现在还是自己 checkout mcpp-index@main,加上 needs: revisions,并把 ref: 设成 ${{ needs.revisions.outputs.index }},这样整次运行用的都是同一个 index 版本。

@Sunrisepeak 改好了

Run 38695300904 failed on a cache HIT, not in the cold path: the cached
libxml2:i386 2.9.14+dfsg-1.3ubuntu3.9 was installed with `dpkg -i` next to
the image's libxml2:amd64 ...3.10, then `apt-get install -f` upgraded it,
and that upgrade's shared changelog was refused. The cause is the key:
`wine-debs-...-v1` names nothing that fills the cache, and the save runs
only on a miss, so the packages were saved once and never again while the
image moved on (the 2026-10-02 CI record, 2.4.4: a cache saved under an
unchanged key is never saved again). `--force-overwrite` let the stale
install through instead of removing it.

- The key carries the runner's ImageVersion; restore-keys hands a new
  image the previous image's packages until main saves its own.
- The cache seeds /var/cache/apt/archives and apt installs, every time.
  A cached package still at the current version is used as is, a newer
  one is fetched, and nothing older than the image is installed, so there
  is no conflict to force through.
- The third-party apt lists are dropped on both paths, since both now run
  `apt-get update`.
- What main saves is what this image installs; `autoclean` drops packages
  no index offers any more, so the cache does not grow with each image.

This PR's own run exercises the stale path: its key misses, and
restore-keys returns the `-v1` cache that failed.
@Sunrisepeak
Sunrisepeak merged commit 3435540 into mcpp-community:main Oct 15, 2026
61 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants