Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
115 commits
Select commit Hold shift + click to select a range
fe3365d
wip: a row's GCC payload as data (gcc-triple); the COFF object format
Sunrisepeak Nov 13, 2026
b53719e
tests/support and the first C++ end-to-end case; mtest 0.7.1
Sunrisepeak Nov 13, 2026
7a22f96
e2e: the migration inventory of the 752 scripts and the keep baseline
Sunrisepeak Nov 13, 2026
52631a4
e2e: the test subsystem as C++ cases (38 scripts)
Sunrisepeak Nov 13, 2026
1bf5e8e
e2e: the build-program subsystem as C++ cases (66 scripts)
Sunrisepeak Nov 13, 2026
b4c8151
e2e: the deps subsystem as C++ cases (49 scripts)
Sunrisepeak Nov 13, 2026
65b9772
e2e: the actions subsystem as C++ cases (37 scripts)
Sunrisepeak Nov 13, 2026
e1ce16a
e2e: the features subsystem as C++ cases (37 scripts)
Sunrisepeak Nov 13, 2026
6f2864b
e2e: the pack subsystem as C++ cases (37 scripts)
Sunrisepeak Nov 13, 2026
d134f1c
e2e: the build subsystem as C++ cases (45 scripts)
Sunrisepeak Nov 13, 2026
1981de4
cfg: interface, the kernel-abi layer's provided interfaces
Sunrisepeak Nov 13, 2026
b2795c8
design: toolchain payloads as data (section 16)
Sunrisepeak Nov 13, 2026
1e0b732
design: gcc 16.2.0 and the 17 trunk snapshot (section 16.4)
Sunrisepeak Nov 13, 2026
b54de53
toolchain: payloads as data, and any package of the index as a toolchain
Sunrisepeak Nov 13, 2026
8929c24
docs: the payload table, a family's versions and trunk snapshots, any…
Sunrisepeak Nov 13, 2026
eeacc5f
design: workspace concurrency, the build directory named by its linea…
Sunrisepeak Nov 13, 2026
2da705c
build directory named by its lineage; lock wait in Finished; split de…
Sunrisepeak Nov 13, 2026
b929f4f
the graph runs mcpp through the build directory's link to it
Sunrisepeak Nov 13, 2026
3176d40
tests: the build directory's lineage, its engine link and an upgrade …
Sunrisepeak Nov 13, 2026
972e17a
design: workspace test feedback, mcpp#927 (section 18)
Sunrisepeak Nov 13, 2026
0f7ae46
e2e: the cli subsystem as C++ cases (17 scripts)
Sunrisepeak Nov 13, 2026
96ef42c
e2e: the modules subsystem as C++ cases (30 scripts)
Sunrisepeak Nov 13, 2026
23d568c
a toolchain named with --toolchain opts a planned row in
Sunrisepeak Nov 13, 2026
e16535f
the planned opt-in counts MCPP_TOOLCHAIN; a carrier reads its row's o…
Sunrisepeak Nov 13, 2026
7448be9
cenv answers by the row's container; cfg(object-format = ...) selects…
Sunrisepeak Nov 13, 2026
6e15c97
tests: case directories under the system's temporary directory
Sunrisepeak Nov 13, 2026
14bcf7e
e2e: the cache subsystem as C++ cases (22 scripts)
Sunrisepeak Nov 13, 2026
61ec3cb
a defined row states its link emulation without its machine; design: …
Sunrisepeak Nov 13, 2026
14c2798
design: the measured UEFI result and the interface-selected optional …
Sunrisepeak Nov 13, 2026
064dc2e
a provider states the link, base and runner of its identities over ei…
Sunrisepeak Nov 13, 2026
fc7462f
a runner named by the environment replaces the requirements of the on…
Sunrisepeak Nov 13, 2026
ac9fba3
build: make the graph's engine link again after a cold build clears t…
Sunrisepeak Nov 13, 2026
e71d37e
e2e: cache 174 is judged as any case again
Sunrisepeak Nov 13, 2026
c65e4a1
e2e: the workspace subsystem as C++ cases (25 scripts)
Sunrisepeak Nov 13, 2026
ac06de8
e2e: the run subsystem as C++ cases (19 scripts)
Sunrisepeak Nov 13, 2026
4f6a4f3
e2e: the cdb subsystem as C++ cases, first part (8 scripts)
Sunrisepeak Nov 13, 2026
871d526
e2e: the cdb subsystem as C++ cases, second part (11 scripts; 4 kept)
Sunrisepeak Nov 13, 2026
3129994
e2e: the cdb subsystem as C++ cases, third part (4 scripts; the llvm …
Sunrisepeak Nov 13, 2026
75cdd3d
e2e: the index subsystem as C++ cases (34 scripts)
Sunrisepeak Nov 13, 2026
9063356
e2e: the self subsystem as C++ cases (17 scripts)
Sunrisepeak Nov 13, 2026
483e071
a compiler without C++ modules refuses the graph's C++ sources before…
Sunrisepeak Nov 13, 2026
44aba3f
an interrupt asks each program to end before ending its unit; waits p…
Sunrisepeak Nov 13, 2026
0062285
test programs by package, the test summary by segment, an index reade…
Sunrisepeak Nov 13, 2026
c6a78db
cli: mcpplibs.cmdline 0.0.4; actions return their status and the run …
Sunrisepeak Nov 13, 2026
f835725
design: implementation record for 2026.11.13.1 (§15.3, §18.3, §19.3)
Sunrisepeak Nov 13, 2026
3083163
docs: test programs by package, the test summary by segment, the size…
Sunrisepeak Nov 13, 2026
463012f
release: 2026.11.13.1
Sunrisepeak Nov 13, 2026
38c689d
build: the engine link reads a replaced image where procfs presents i…
Sunrisepeak Nov 13, 2026
2249ca3
canaries: tests/canary (c, cxx), the matrix with its measured expecta…
Sunrisepeak Nov 13, 2026
aad9ae4
AGENTS.md: the canaries and their matrix
Sunrisepeak Nov 13, 2026
5cf1223
spec test B1.2: programs = "package", and the note of "directory"
Sunrisepeak Nov 13, 2026
e6db67d
test parts named by their path below the program's directory; a test …
Sunrisepeak Nov 13, 2026
0f257a6
docs: a package's parts by their path; design record
Sunrisepeak Nov 13, 2026
9043af8
e2e: test programs by package and the note of directory (1081, 1082),…
Sunrisepeak Nov 13, 2026
4d2eff9
run: a program that ends during an interrupt ends its unit with it
Sunrisepeak Nov 13, 2026
6ac6b2d
e2e: the openkal subsystem as C++ cases (45 scripts; 6 kept beside th…
Sunrisepeak Nov 13, 2026
1e5d7ee
a compiler without C++ modules builds the C++ units that need none
Sunrisepeak Nov 13, 2026
e08e079
A base-none provider carries the tools its conventions name; a compil…
Sunrisepeak Nov 13, 2026
25ce7b2
lineage: the base as stated names the configuration; its contents evo…
Sunrisepeak Nov 13, 2026
f6af368
e2e 925: a base rewritten in place is built again in its directory
Sunrisepeak Nov 13, 2026
6a24d70
A build of a platform's own row reads its view, without the tools onl…
Sunrisepeak Nov 13, 2026
6a9889b
e2e: file times through one portable helper; the canaries' Linux mach…
Sunrisepeak Nov 13, 2026
7fc4a60
pack: a system a platform defines is its row; ELF32 runtime facts; a …
Sunrisepeak Nov 13, 2026
b337a22
spec packaging 2.4: a system a platform defines is its row; a seal's …
Sunrisepeak Nov 13, 2026
d0f3ecc
tests: an ELF symbol's definition and binding, and DT_RPATH alone
Sunrisepeak Nov 13, 2026
6bd9466
e2e: the runtime subsystem as C++ cases (32 scripts; 2 kept beside th…
Sunrisepeak Nov 13, 2026
14771fa
e2e: the web subsystem as C++ cases (4 scripts; 4 kept beside their c…
Sunrisepeak Nov 13, 2026
4b9d419
e2e: the baremetal subsystem as C++ cases (3 scripts)
Sunrisepeak Nov 13, 2026
de88d56
e2e: the repository's consistency checks as a unit test; remove and u…
Sunrisepeak Nov 13, 2026
82faae2
e2e: 845 (--play-game restores the terminal) as a case of e2e/cli
Sunrisepeak Nov 13, 2026
ce76b1a
e2e: compare a JSON string with a string_view through its std::string
Sunrisepeak Nov 13, 2026
3ecc388
e2e: the target subsystem as C++ cases (39 scripts; 16 kept beside th…
Sunrisepeak Nov 13, 2026
36a69a4
e2e: the toolchain subsystem as C++ cases (37 scripts; 5 kept beside …
Sunrisepeak Nov 13, 2026
949f2d9
ci: the matrix asks as it builds; the canaries are not tests of the r…
Sunrisepeak Nov 13, 2026
4a4ea8d
e2e: the android subsystem as C++ cases (6 scripts; 5 kept beside the…
Sunrisepeak Nov 13, 2026
be4ef16
e2e: the macos subsystem as C++ cases (8 scripts)
Sunrisepeak Nov 13, 2026
376be38
test: several patterns select every test one of them names
Sunrisepeak Nov 13, 2026
e58d310
test: a case states where it runs and what it needs as mtest 0.8.0 at…
Sunrisepeak Nov 13, 2026
b3f333c
test: the Windows e2e scripts are C++ cases (migration batch 24)
Sunrisepeak Nov 13, 2026
3d4a000
ci: named cases run from the build's test archive; mtest engine 0.8.0
Sunrisepeak Nov 13, 2026
fea1949
docs: places and capabilities of a case (SPEC-017 2.1); the test arch…
Sunrisepeak Nov 13, 2026
daf72f9
fix: config.toml is replaced whole, never rewritten in place
Sunrisepeak Nov 13, 2026
0768560
test: four cases read the same under libc++, MSVC STL and libstdc++
Sunrisepeak Nov 13, 2026
c808f6f
ci: an e2e program has 1200 s in the unit jobs
Sunrisepeak Nov 13, 2026
cb9dc43
ci: the set follows the event, shards follow the work, a gate per host
Sunrisepeak Nov 13, 2026
cfb4415
docs: the CI's trigger model (section 5.11) and the config.toml fix i…
Sunrisepeak Nov 13, 2026
0b4c920
fix: a reader of config.toml is closed before the file is replaced
Sunrisepeak Nov 13, 2026
7117cb3
test: the e2e cases run on Windows as their scripts did
Sunrisepeak Nov 13, 2026
ee425d5
ci: unit jobs have 90 minutes; the macOS 721 step is the unit job's case
Sunrisepeak Nov 13, 2026
ff49e8b
fix: a rename over a home's file waits up to two seconds for its readers
Sunrisepeak Nov 13, 2026
5411c3b
test: a case that sets the default toolchain does it in its own home
Sunrisepeak Nov 13, 2026
ab1669f
test: 842, 849 and 681 run on Windows as their scripts did
Sunrisepeak Nov 13, 2026
fd6386d
ci: a canary cell that differs prints its log's resolution and failed…
Sunrisepeak Nov 13, 2026
663b3ee
docs: the CHANGELOG states the Windows config.toml writer
Sunrisepeak Nov 13, 2026
61034df
fix: mcpp test runs a case that holds the machine with no other test …
Sunrisepeak Nov 14, 2026
7671f19
test: the e2e cases that hold the machine are suites that state it
Sunrisepeak Nov 14, 2026
970cac1
fix: an upgrade takes its build directory over; the self-review's fin…
Sunrisepeak Nov 14, 2026
dfb6577
mtest 0.8.3: mcpp scaffolds with it, and the engine benchmark times e…
Sunrisepeak Nov 14, 2026
6a5a047
ci: a canary cell that fails where its row states ok is run again wit…
Sunrisepeak Nov 14, 2026
cacc884
fix: the home's file writer and reader name no system
Sunrisepeak Nov 14, 2026
03a863a
test: mcpp test orders, divides and shards a run by the durations its…
Sunrisepeak Nov 14, 2026
23098b9
ci: the Linux tests build once beside the build and run in shards; th…
Sunrisepeak Nov 14, 2026
13b87f5
ci: the archive stage takes the permissions its caller grants
Sunrisepeak Nov 14, 2026
e1634e8
test: a test no run measured takes its nearest measured directory; th…
Sunrisepeak Nov 14, 2026
a54c7fb
refactor: registry ownership, preparation intent, runner hand-off and…
Sunrisepeak Nov 14, 2026
efeb1f2
test: the package's programs built elsewhere are named by the environ…
Sunrisepeak Nov 14, 2026
37a74f6
fix: a payload that starts through its home's loader runs on the home…
Sunrisepeak Nov 14, 2026
7aaba2f
deps: mtest 0.8.5, whose end-to-end outcomes say when an output was c…
Sunrisepeak Nov 14, 2026
2950947
fix: a reader of a file being replaced on Windows waits for the repla…
Sunrisepeak Nov 14, 2026
a5a1de8
fix: the run of an archive asks for no link program, takes the platfo…
Sunrisepeak Nov 14, 2026
9cb49fd
home: a reader and a writer of a home's file retry the one refusal an…
Sunrisepeak Nov 14, 2026
90de27f
fix: the self-review's findings: the gate keeps no record in the shar…
Sunrisepeak Nov 14, 2026
0a19eff
test: the replaced-whole case says what its first reader that missed …
Sunrisepeak Nov 14, 2026
b2d159a
test: a case that asserts a replay holds the machine (extensions 218)…
Sunrisepeak Nov 14, 2026
3dbee70
fix: config.toml is written as given, and a value is set before eithe…
Sunrisepeak Nov 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
326 changes: 326 additions & 0 deletions .agents/docs/2026-11-12-ecosystem-architecture-optimization-design.md

Large diffs are not rendered by default.

222 changes: 222 additions & 0 deletions .agents/docs/2026-11-14-ci-and-release-time-cost-design.md

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion .agents/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ superseded_by: 2026-09-07-....md # when status is superseded
---
```

360 records.
361 records.

## By subject

Expand All @@ -42,6 +42,10 @@ Records that declare one. Everything else is listed by date below.

- [BMI publication, compiler capacity and active download budgets](2026-11-06-bmi-publication-and-compiler-cap-closeout.md) — active

### ci

- [CI 与发布的时间成本:按测量调度的测试、分片、并行发布](2026-11-14-ci-and-release-time-cost-design.md) — active

### compiler-scheduling

- [Compiler attempt lifetime and output recovery](2026-11-06-compiler-attempt-recovery.md) — active
Expand Down Expand Up @@ -193,6 +197,7 @@ Records that declare one. Everything else is listed by date below.

### 2026-11

- [CI 与发布的时间成本:按测量调度的测试、分片、并行发布](2026-11-14-ci-and-release-time-cost-design.md) — active
- [The three-plane platform architecture: mcpp × openkal × xim](2026-11-12-three-plane-platform-architecture-design.md) — superseded by [2026-11-12-ecosystem-architecture-optimization-design.md](2026-11-12-ecosystem-architecture-optimization-design.md)
- [生态架构优化方案:四个平面的收敛、已合入项的纠正与新系统的准入(mcpp × openkal × xlings)](2026-11-12-ecosystem-architecture-optimization-design.md) — active
- [测试与依赖解析补充方案:mcpp、mcpp test、mtest、mcpp-ide](2026-11-10-test-and-resolution-supplement-design.md) — active
Expand Down
27 changes: 19 additions & 8 deletions .agents/skills/mcpp-release/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,26 @@ Tag push 会自动触发 `release.yml` workflow。

### 4. 监控 Release CI

Release workflow 包含**四个平台**的构建,外加一个生态发布 job:
Release workflow 的四个平台构建**同时开始**,各自把归档留作 artifact;`create-release`
在四个构建都通过后一次创建带全部归档的 GitHub release(设计 2026-11-14):

| Job | 平台 | 产物 | 依赖 |
|-----|------|------|------|
| `build-release` | Linux x86_64 | `mcpp-X.Y.Z-linux-x86_64.tar.gz` | 无(先执行) |
| `build-linux-aarch64` | Linux aarch64(交叉) | `mcpp-X.Y.Z-linux-aarch64.tar.gz` | 等 Linux x86_64 完成 |
| `build-macos` | macOS ARM64 | `mcpp-X.Y.Z-macosx-arm64.tar.gz` | 等 Linux 完成 |
| `build-windows` | Windows x86_64 | `mcpp-X.Y.Z-windows-x86_64.zip` | 等 Linux 完成 |
| `publish-ecosystem` | — | 镜像到 xlings-res 双端 + 开索引 bump PR | 等**全部四个**构建完成 |
| `canaries` | — | 生态项目(xlings、mcppls)用候选版本构建 | 仅手动发布且勾选 `canaries` 时运行 |
| `build-release` | Linux x86_64 | `mcpp-X.Y.Z-linux-x86_64.tar.gz`、源码包、`mcpp.lua`、`install.sh` | 无 |
| `build-linux-aarch64` | Linux aarch64(交叉) | `mcpp-X.Y.Z-linux-aarch64.tar.gz` | 无 |
| `build-macos` | macOS ARM64 | `mcpp-X.Y.Z-macosx-arm64.tar.gz` | 无 |
| `build-windows` | Windows x86_64 | `mcpp-X.Y.Z-windows-x86_64.zip` | 无 |
| `create-release` | — | GitHub release、覆盖全部归档的 `SHA256SUMS` | 四个构建(及运行时的 canaries) |
| `release-manifest` | — | `mcpp-release.json` | `create-release` |
| `publish-ecosystem` | — | 镜像到 xlings-res 双端 + 开索引 bump PR | `release-manifest` |

canaries 默认不运行(tag push 与未勾选的手动发布):xlings 与 mcppls 的构建约 40 分钟,
由各项目在发布后以自己的 CI 固定新版本验证。需要在创建 release 前验证时,手动发布:

```bash
gh workflow run release.yml --repo mcpp-community/mcpp -f canaries=true
```

`build-linux-aarch64` 是两段式的(bootstrap 先构出本 release 的 x86_64 mcpp,再用它交叉构建
aarch64),因为 bootstrap 装的是**上一个已发布版本**,可能不认新特性。
Expand All @@ -138,7 +149,7 @@ gh run view <run-id>
# 如果失败,下载日志分析
gh api repos/mcpp-community/mcpp/actions/runs/<run-id>/logs \
-H "Accept: application/vnd.github+json" > /tmp/release-logs.zip
unzip -p /tmp/release-logs.zip "build + upload (linux _ x86_64)/8_Smoke-test the bundled tarball.txt"
unzip -p /tmp/release-logs.zip "build (linux _ x86_64)/8_Smoke-test the bundled tarball.txt"
```

### 5. 验证 Release 产物
Expand Down Expand Up @@ -189,7 +200,7 @@ release 规则验证最终资产,不要套用 Linux 的 strip 判断。

### publish-ecosystem:镜像 + 索引(发布的后半程)

四个构建 job 全绿后自动执行,做两件事:
`release-manifest` 封存之后自动执行,做两件事:

1. **镜像到 `xlings-res/mcpp` 双端**(GitHub + GitCode),由
`.github/tools/mirror_res.sh` 完成 —— 单 leg 内资产**并发上传**
Expand Down
92 changes: 92 additions & 0 deletions .github/actions/e2e-cases/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
name: e2e-cases
description: >
Named cases of the C++ e2e suite, each held to its `ok` line: a case that is
skipped (a capability absent, another platform) or fails fails the step, so a
job that exists to run a case cannot pass without running it. The cases run
from the test archive build.yml wrote for the host (`mcpp-tests-<host>`,
`mcpp test --archive`, docs/08): no job that runs them builds them, and a
host with Visual Studio masked could not.
inputs:
cases:
description: the cases, one `<suite>/<case>` per line
required: true
mcpp:
description: the mcpp that runs the tests
required: true
host:
description: the host of the archive (linux-x86_64, windows-x86_64)
required: true
from-main:
description: >
'true': the archive of main's last successful CI run, for a workflow that
runs outside it (ci-fresh-install); otherwise this run's.
required: false
default: 'false'
under-test:
description: >
The mcpp the cases test: MCPP_E2E_MCPP, which the cases' support reads
before the archive's program, and MCPP_BIN_MCPP, which an archive written
with --no-programs takes. Empty: the archive's own build.
required: false
default: ''
token:
description: a token that reads this repository's actions
required: false
default: ${{ github.token }}

runs:
using: composite
steps:
- name: The tests of this run
if: inputs.from-main != 'true'
uses: actions/download-artifact@v4
with:
name: mcpp-tests-${{ inputs.host }}
path: ${{ runner.temp }}/mcpp-tests

- name: The tests of main's last CI run
if: inputs.from-main == 'true'
shell: bash
env:
GH_TOKEN: ${{ inputs.token }}
HOST: ${{ inputs.host }}
run: |
set -euo pipefail
run=$(gh run list -R "$GITHUB_REPOSITORY" --workflow ci.yml --branch main --status success --limit 1 \
--json databaseId -q '.[0].databaseId')
[ -n "$run" ] || { echo "::error::no successful CI run of main holds the tests"; exit 1; }
rm -rf "$RUNNER_TEMP/mcpp-tests"
gh run download "$run" -R "$GITHUB_REPOSITORY" -n "mcpp-tests-$HOST" -D "$RUNNER_TEMP/mcpp-tests"
echo "the tests of main's run $run"
- name: The cases
shell: bash
env:
CASES: ${{ inputs.cases }}
RUNNER_MCPP: ${{ inputs.mcpp }}
UNDER_TEST: ${{ inputs.under-test }}
run: |
set -euo pipefail
cases=()
while IFS= read -r c; do
c="${c#"${c%%[![:space:]]*}"}"; c="${c%"${c##*[![:space:]]}"}"
if [ -n "$c" ]; then cases+=("$c"); fi
done <<< "$CASES"
[ "${#cases[@]}" -gt 0 ] || { echo "::error::no case named"; exit 1; }
args=(--archive "$RUNNER_TEMP/mcpp-tests/mcpp-tests.tar.gz")
for c in "${cases[@]}"; do args+=(--case "$c"); done
# The system's own spelling of the path: mcpp reads MCPP_BIN_MCPP
# itself, and a Windows mcpp does not read an MSYS path.
if [ -n "$UNDER_TEST" ]; then
under="$UNDER_TEST"
if command -v cygpath >/dev/null 2>&1; then under="$(cygpath -w "$under")"; fi
export MCPP_E2E_MCPP="$under" MCPP_BIN_MCPP="$under"
fi
log="$RUNNER_TEMP/e2e-cases.log"
status=0
"$RUNNER_MCPP" test "${args[@]}" 2>&1 | tee "$log" || status=$?
for c in "${cases[@]}"; do
tr -d '\r' < "$log" | grep -qxF " ok $c" || { echo "::error::$c did not pass (a skip or a failure; its line above)"; status=1; }
done
exit "$status"
6 changes: 4 additions & 2 deletions .github/actions/e2e-mtest/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ description: >
inputs:
host:
description: the host's name in the stores' artifact names (linux, macos, windows)
description: >
the host's name in the stores' artifact names (linux, macos, windows), or
`*` for every host's (the plan of ci.yml)
required: true
token:
description: a token that reads this repository's actions
Expand Down Expand Up @@ -55,7 +57,7 @@ runs:
# Another host's own sources (src/native/windows/...) run on no Linux test,
# so its suite has no map and every test of it is affected.
- name: The coverage map
if: inputs.host == 'linux'
if: inputs.host == 'linux' || inputs.host == '*'
shell: bash
env:
GH_TOKEN: ${{ inputs.token }}
Expand Down
146 changes: 146 additions & 0 deletions .github/actions/mcpp-unit/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
name: mcpp-unit
description: >
The unit and C++ e2e tests by `mcpp test` (docs/08 "The order of a run";
design 2026-11-14): the measured history of main's last CI run taken into the
run store, so that the tests run longest first, a part longer than its share
runs as groups of its cases (`--split auto`) and `--shard` assigns tests by
duration; on a re-run of a failed job, only what its previous attempt failed
(`--failed`); the job's own runs kept as `mtest-unit-<name>-a<attempt>`.
Run it after use-built-mcpp, from the repository's root.
inputs:
name:
description: the job's name in the stores' artifact names (linux-1, macos-15, windows)
required: true
history:
description: >
the stores of main's last CI run to read the measured durations from
(`mtest-unit-<history>*`); empty when the job was given its history
(the shards of one run take it from their archive job)
required: false
default: ''
archive:
description: the test archive to run (`mcpp test --archive`); empty to build the tests here
required: false
default: ''
shard:
description: I/N, this job's shard of the tests (`mcpp test --shard`)
required: false
default: ''
since:
description: the commit a pull request's change is read from (`mcpp test --since`)
required: false
default: ''
patterns:
description: the tests to run, as `mcpp test` patterns separated by spaces; empty for all
required: false
default: ''
mcpp:
description: the mcpp that runs the tests; empty for this commit's (MCPP_FRESH)
required: false
default: ''
timeout:
description: the seconds a test may run (`mcpp test --timeout`)
required: false
default: '1200'
stores:
description: the stores to keep, relative to the workspace, separated by spaces
required: false
default: target/mtest
token:
description: a token that reads this repository's actions
required: false
default: ${{ github.token }}

runs:
using: composite
steps:
- name: The measured history of main's last CI run
if: inputs.history != ''
shell: bash
env:
GH_TOKEN: ${{ inputs.token }}
KEY: ${{ inputs.history }}
run: |
set -uo pipefail
py=python3; command -v python3 >/dev/null 2>&1 || py=python
run=$(gh run list -R "$GITHUB_REPOSITORY" --workflow ci.yml --branch main --status success --limit 1 \
--json databaseId -q '.[0].databaseId' 2>/dev/null || true)
if [ -z "$run" ]; then echo "no successful run of main: the tests run in the order they are listed"; exit 0; fi
d="$RUNNER_TEMP/unit-history"
rm -rf "$d"
if ! gh run download "$run" -R "$GITHUB_REPOSITORY" -p "mtest-unit-$KEY*" -D "$d" 2>/dev/null; then
echo "main's run $run kept no store for $KEY: the tests run in the order they are listed"; exit 0
fi
"$py" .github/tools/test_history.py take target/mtest "$d" "$d"/*/
# A RE-RUN RUNS WHAT FAILED. The store of the attempt before this one, when
# it kept one, names what failed; a job that failed before its tests ran
# kept none and runs them all again.
- name: The attempt before this one
if: github.run_attempt != '1'
shell: bash
env:
GH_TOKEN: ${{ inputs.token }}
NAME: ${{ inputs.name }}
run: |
set -uo pipefail
py=python3; command -v python3 >/dev/null 2>&1 || py=python
prev="mtest-unit-$NAME-a$((GITHUB_RUN_ATTEMPT - 1))"
d="$RUNNER_TEMP/unit-previous"
rm -rf "$d"
if gh run download "$GITHUB_RUN_ID" -R "$GITHUB_REPOSITORY" -n "$prev" -D "$d" 2>/dev/null \
&& [ -f "$d/index.ndjson" ]; then
"$py" .github/tools/test_history.py take target/mtest "$d"
echo "MCPP_UNIT_FAILED=1" >> "$GITHUB_ENV"
echo "the attempt before kept $prev: what it failed runs again"
else
echo "the attempt before kept no store: every test runs"
fi
- name: The tests via `mcpp test`
shell: bash
env:
ARCHIVE: ${{ inputs.archive }}
SHARD: ${{ inputs.shard }}
SINCE: ${{ inputs.since }}
PATTERNS: ${{ inputs.patterns }}
TIMEOUT: ${{ inputs.timeout }}
RUNS: ${{ inputs.mcpp }}
run: |
set -euo pipefail
args=(test --timeout "$TIMEOUT" --split auto)
# THE PROGRAM THE TESTS RUN IS THIS COMMIT'S, AS BUILD.YML BUILT IT
# (rule R1): it is not built again here (`--no-programs`), and an
# archive written without it takes it from the same variable. A native
# path: on Windows the variable is read by mcpp and the tests, not bash.
fresh="$MCPP_FRESH"
if command -v cygpath >/dev/null 2>&1; then fresh="$(cygpath -w "$fresh")"; fi
export MCPP_BIN_MCPP="${MCPP_BIN_MCPP:-$fresh}"
if [ -n "$ARCHIVE" ]; then args+=(--archive "$ARCHIVE"); else args+=(--no-programs); fi
if [ -n "${MCPP_UNIT_FAILED:-}" ]; then
args+=(--failed)
else
[ -z "$SHARD" ] || args+=(--shard "$SHARD")
[ -z "$SINCE" ] || args+=(--since "$SINCE")
# shellcheck disable=SC2206 -- the patterns are words
[ -z "$PATTERNS" ] || args+=($PATTERNS)
fi
echo "mcpp ${args[*]}"
"${RUNS:-$MCPP_FRESH}" "${args[@]}"
# The job's own runs, and not the history it was given, are kept.
- name: The runs of this job
if: always()
shell: bash
env:
STORES: ${{ inputs.stores }}
run: |
py=python3; command -v python3 >/dev/null 2>&1 || py=python
for s in $STORES; do [ ! -d "$s" ] || "$py" .github/tools/test_history.py own "$s" "$GITHUB_RUN_ID"; done
- uses: ./.github/actions/test-report
if: always()
with:
name: mtest-unit-${{ inputs.name }}-a${{ github.run_attempt }}
stores: ${{ inputs.stores }}
3 changes: 2 additions & 1 deletion .github/actions/use-built-mcpp/use.sh
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ if [ -n "$tc" ]; then
fi

{
echo "MCPP_BOOT=$boot"
# The released binary install_pinned_mcpp.sh named, when it named one.
echo "MCPP_BOOT=${MCPP_BOOT:-$boot}"
echo "MCPP=$bin"
echo "MCPP_FRESH=$bin"
if [ -n "${XLINGS_BIN:-}" ]; then echo "MCPP_VENDORED_XLINGS=$XLINGS_BIN"; fi
Expand Down
6 changes: 4 additions & 2 deletions .github/release-canaries.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Release canaries (the 2026-09-28 ecosystem design, WS10).
#
# Projects of this ecosystem built with the candidate mcpp before a release is
# tagged: release.yml runs .github/workflows/release-canaries.yml first, and a
# canary that fails blocks the tag.
# created: a release started by hand with `canaries` (release.yml) runs
# .github/workflows/release-canaries.yml beside its builds, and a canary that
# fails blocks the release. A tag pushed, or a release started without it,
# runs none (design 2026-11-14: their build took 48 of 109 minutes).
#
# Only the ecosystem's own repositories are canaries. A downstream project (a
# user's application, or a fork of one) validates a release in its own pull
Expand Down
26 changes: 26 additions & 0 deletions .github/tools/built_artifact.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env bash
# THE PROGRAM A BUILD MADE, AS THE BUILD REPORTS IT.
#
# built_artifact.sh <mcpp> <name> [build arguments...]
#
# Runs `<mcpp> build --message-format json [arguments]` and prints the absolute
# path of the artifact named <name>, from the build's `artifact` events
# (docs/50-machine-output.md §9): one line per product, whose object has one
# `path`. Read with grep and sed (`-E`, as GNU and BSD sed read it), so that a
# machine with no JSON reader (the hermetic container) can ask it. The build's narration stays on standard
# error. A failed build, or one that reports no such artifact, exits non-zero.
#
# Instead of a search of target/: a self-hosting build keeps the engine it
# runs under target/<triple>/<fingerprint>/engine/epoch-N/mcpp, and a search
# for a file named mcpp took that copy (an x86_64 program) for the product of
# an aarch64 build (2026-11-14).
set -euo pipefail
[ $# -ge 2 ] || { echo "usage: $0 <mcpp> <name> [build arguments...]" >&2; exit 2; }
mcpp=$1; name=$2; shift 2
report=$(mktemp)
trap 'rm -f "$report"' EXIT
"$mcpp" build --message-format json "$@" > "$report"
found=$(grep -F '"event":"artifact"' "$report" | grep -F "\"name\":\"$name\"" \
| sed -nE 's/.*"path":"(([^"\\]|\\.)*)".*/\1/p' | tail -1 | sed 's/\\\\/\\/g' || true)
[ -n "$found" ] || { echo "the build reported no artifact named $name" >&2; exit 1; }
printf '%s\n' "$found"
Loading
Loading